Save-Point
KyoDiscounts XP - Printable Version

+- Save-Point (https://www.save-point.org)
+-- Forum: Material Development (https://www.save-point.org/forum-8.html)
+--- Forum: Scripts Database (https://www.save-point.org/forum-39.html)
+---- Forum: RPGMaker XP (RGSS) Engine (https://www.save-point.org/forum-116.html)
+---- Thread: KyoDiscounts XP (/thread-6184.html)

Pages: 1 2 3 4


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-14-2019

Well, I decided to post the latest version of KyoDiscounts XP 1.5.0, even if it is some sort of beta release.

Edit: I had to include some method calls to get rid of the appraisal options window and the appraisal result window contents.
Another Edit: I had to reduce some windows sizes to fit the screen... =_=

Code:
# * KyoDiscounts XP
#   Scripter : Kyonides-Arkanthes
#   v1.5.0 - 2019-01-13

#   Whenever you obtain a discount card, such discount will be applied to all
#   of your purchases if you have picked a card till it expires after a certain
#   number of steps. Additional steps will be quickly added to your current card
#   whenever you purchase any additional card of the same kind.

#   One coupon will be spent every single time you purchase any specific item,
#   you will need another one to purchase a different item later on.
#   The discount card or coupon price is used to calculate the corresponding
#   discount on every single purchase the player makes with it.

#   Place this script below KItemRefill XP or KyoScriptPack Item XP if you
#   included any of those scripts in your current game project.

#   Now you can also setup exclusive store discount cards as well. Just keep in
#   mind that you will need to setup the in game variable you picked so it will
#   be able to store the Exclusive Store Code (an Integer) before you can add
#   the shop event command. Common stores don't need any Store Code at all.

#   Besides the player can also place orders to get an item that is supposed to
#   be found at another store only. The player will be charged an extra fee, but
#   he or she won't need to go back to another store. The player would only need
#   to keep walking for a while before the goods are available at the store.
#   Now the required steps for each placed order will be automatically increased
#   between 0% and 50%, making it look a bit random but also kind of realistic.

# * Unknown Item or Weapon or Armor Appraisals *

#   Use the Game Variable defined in the STORECODEVARID Constant to store the
#   Shop ID that will include the appraisal service.
#   Use the MYSTERIOUS series of Arrays to include as many IDs of unknown items
#   or weapons or armors that will serve as fillers till they get replaced by
#   the actual goods they represent.
#   Follow the Instructions included in the APPRAISALS Hash to define all
#   conditions that will affect an appraiser's task of identifying the item.

#   Script Calls   #

#   $game_party.discount_cards_expire
#      Makes all Discount Cards expire as part of the game's plot.

#   $game_party.disc_card_expire(Card_ID)
#      Makes an specific Discount Card expire as part of the game's plot.

#   KyoShopOrders << [Percent1, Percent2, etc.]
#      Defines a Commission percent for every Item in the Place Order List.

#   KyoShopOrders.steps = [Steps1, Steps2, etc.]
#   KyoShopOrders.steps += [Steps5, Steps6, etc.]
#      Defines Steps required by every Order in the Place Order List.
#      The 2nd call will be required only if you couldn't include all steps.

#   KyoShop.scarcity_lvl = 0 or higher
#     Define all prices and maximum number of units per shop item.
#     0 means no scarcity, 1 or higher reflects how severe it is.
#     You also have to configure the @scarce_limits hash in order to predefine
#     :price and :max per scarcity level. The maximum scarcity level depends on
#     how many values you entered in both :price and :max arrays.
#     In few words, you define the maximum scarcity level ever possible!

module KyoShop
  # Maximum number of units for each shop item
  NUMBERMAX = 99
  # Button that will open the Discount window while on the shop menu
  DISCOUNTBUTTON = Input::A
  # Add Discount Card Object IDs
  DISCOUNT_IDS = [33, 34]
  # Add Discount Coupon Object IDs
  COUPON_IDS = [36, 37]
  # Maximum Steps before Discount Card expires : ID => Steps
  STEPS = { 33 => 500, 34 => 300, 35 => 150 }
  # Exclusive Stores In Game Variable ID
  STORECODEVARID = 1
  # Exclusive Stores List : Object ID => Exclusive Store Code
  EXCLUSIVESTORES = { 35 => 102 }
  # Switch ID : deactivates Store to add Goods found elsewhere
  GOODSSWITCHID = 1
  # Store IDs for stores where you have invested some gold
  INVESTSTOREIDS = [101]
  # Maximum Number of Shares & Share Price
  SHARESMAXMIN = [10000, 100]
  INVESTMENTS = {} # Store Investments - Do Not Edit This Line
  INVESTMENTS.default = {} # Do Not Edit This Line
  # Available Improvements #
  # :discount : [:discount, 25]
  # :goods    : [:goods, 'i10', 'w4', 'a6']
  # :orders   : [:orders, 'i11', 'w5', 'a7']
  # [Store ID] = { Shares => Prize, Shares => Another Prize, etc. }
  INVESTMENTS[101] = { 50 => [:goods,'i10','w5','a6'], 100 => [:discount,10] }
  APPRAISALS = {} # Do Not Edit This Line!
  # [Store ID] = { appraisal cost => $, estimate cost => $, success rate => %,
  #            bad result => "item1", goods => [item4, weapon2, armor3, etc.] }
  APPRAISALS[101] = { :cost => 150, :test_cost => 75, :rate => 10,
                      :default => 'i1', :goods => ['i2','i3','i9','i10'] }
  # Add Item IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSITEMS = []
  # Add Weapon IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSWEAPONS = []
  # Add Armor IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSARMORS = []
  @scarce_limits = {
    :price  => [0, 25, 50, 100, 250, 350, 500, 650, 800],
    :max => [NUMBERMAX, NUMBERMAX - 10, NUMBERMAX - 25, NUMBERMAX - 35,
        NUMBERMAX - 50, NUMBERMAX - 65, NUMBERMAX - 80, NUMBERMAX - 90, 1]
    #:item => [1, 2, 3, 4, 5, 6],
    #:weapon => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
    #:armor => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
  }
  @scarce_lvl = 0 # Initial Level
  def self.current_item_max() @scarce_limits[:max][@scarce_lvl] end
  def self.current_price_max() @scarce_limits[:price][@scarce_lvl] end
  def self.scarcity_limits() @scarce_limits end
  def self.scarcity_lvl() @scarce_lvl end
  def self.scarcity_lvl=(lvl) @scarce_lvl = lvl end
end

module KyoShopLabels
  # Basic Shop Command Labels
  BASIC = ["Buy", "Sell", "Exit"]
  MOREOPTIONS = "Options"
  # Buy Stuff & Place Order & Pick Up Items Label
  BUYPLACEPICKUP = ['Buy Items', 'Place Order', 'Pick Up Items',
                    'Appraise', 'Invest']
  # Subtotal, Commission Percent and Total Amount
  PRICELABELS = ['Subtotal', 'Commission %', 'Total']
  # Place an Order Label
  PLACEORDER = 'Do you wish to place an order?'
  # Pick Up Order Label
  PICKUPORDER = 'Do you want to pick up an order?'
  # No Order Found Label
  NOORDERFOUND = 'There is nothing left, boss!'
  # Available Discounts Label
  SOMEDISCOUNTS = 'Press A to get a discount'
  # No Discount Available Label
  NODISCOUNTS = 'No Discount Available'
  # Select a Discount Card or Coupon Label
  SELECTDISCOUNT = 'Choose a Card or Coupon'
  # Apply Discount Label
  APPLYDISCOUNT = "Discount Applied %s%"
  # Warning about Extra Fees for Placing Orders
  FEESAPPLY = 'Extra Fees Apply'
  # Discount Card's Steps Left Label
  STEPSLEFT = " %s steps left."
  # Investment Label...
  INVESTMENT = 'Want to invest in this store?'
  # Share Number Label
  SHARES = 'Share Number'
  # Adquired or Purchased Shares Label
  TOTALSHARES = 'Total Shares'
  # Pick Item to be Appraised Label
  APPRAISALMENULABEL = "Appraisal Menu"
  # Appraisal Window Labels
  APPRAISALLABELS = ["Quick Test Cost", "Normal Cost"]
  # Appraisal Options Labels
  APPRAISALOPTIONS = ["Quick Test", "Detailed Test", "Cancel"]
  # Appraisal End Result Labels
  APPRAISALRESULTLABELS = [
    "The item at hand is nothing else but... %s",
    "I think it might be worth some... %s"
  ]
end
# DO NOT EDIT ANYTHING ELSE #
module KyoShopOrders
  @commissions = []
  @steps = []
  class << self
    attr_accessor :store_event_id, :goods_id
    attr_reader :steps, :commissions
    def steps=(val) @steps = val.map {|n| n + rand((n / 2) + 2) } end
    def <<(val)
      @commissions += val
      @commissions = @commissions.flatten
    end
  end
end

module WindowModule
  def appear
    self.active = true
    self.visible = true
  end

  def disappear
    self.active = false
    self.visible = false
  end
end

class Game_System
  attr_accessor :shop_goods
  attr_reader :placed_orders, :shop_shares
  alias kyon_discounts_gm_sys_init initialize
  def initialize
    @shop_goods = []
    @placed_orders = {}
    @placed_orders.default = []
    @shop_shares = {}
    @shop_shares.default = 0
    kyon_discounts_gm_sys_init
  end

  def disc_store?(disc_id) !KyoShop::EXCLUSIVESTORES[disc_id] end

  def excl_disc_store?(disc_id)
    exclusive = KyoShop::EXCLUSIVESTORES[disc_id]
    $game_variables[KyoShop::STORECODEVARID] == exclusive
  end

  def check_shares(shop_id)
    results = []
    shares = @shop_shares[shop_id]
    investments = KyoShop::INVESTMENTS[shop_id]
    limits = KyoShop::INVESTMENTS[shop_id].keys.sort
    results = investments.select{|limit| shares >= limit[0] }.map {|r| r[1] }
  end
end

class Game_Party
  attr_reader :discounts
  alias kyon_discounts_gm_party_init initialize
  alias kyon_discounts_gm_party_gain_item gain_item
  def initialize
    @discounts = {}
    kyon_discounts_gm_party_init
  end

  def gain_item(item_id, n)
    kyon_discounts_gm_party_gain_item(item_id, n)
    return if item_id == 0 or n == 0
    return unless KyoShop::DISCOUNT_IDS.include?(item_id)
    if @discounts[item_id]
      @discounts[item_id] += KyoShop::STEPS[item_id]
      @items[item_id] = 1
    else
      @discounts[item_id] = KyoShop::STEPS[item_id]
    end
  end

  def check_discounts
    unless @discounts.empty?
      for did in KyoShop::DISCOUNT_IDS
        next unless @discounts[did] and @discounts[did] > 0
        return true if $game_system.disc_store?(did)
        return true if $game_system.excl_disc_store?(did)
      end
    end
    for cid in KyoShop::COUPON_IDS
      next unless item_number(cid) > 0
      return true if $game_system.disc_store?(cid)
      return true if $game_system.excl_disc_store?(cid)
    end
    return false
  end

  def decrease_discounts
    KyoShop::DISCOUNT_IDS.each {|n| next unless @discounts[n]
      @discounts[n] -= 1 if @discounts[n] > 0 }
  end

  def discount_cards_expire
    KyoShop::DISCOUNT_IDS.each {|n| @discounts[n] = 0 if @discounts[n] }
  end

  def disc_card_expire(dc_id) @discounts[dc_id] = 0 end
end

class Game_Player
  alias kyon_discounts_coupons_gm_player_increase_steps increase_steps
  def increase_steps
    kyon_discounts_coupons_gm_player_increase_steps
    $game_party.decrease_discounts
  end
end

class Window_Selectable
  include WindowModule
end

class Window_Help
  def set_text(item_id, text=nil, align=0)
    if item_id.is_a?(String)
      if KyoShop::DISCOUNT_IDS.include?(KyoShopOrders.goods_id)
        steps = $game_party.discounts[KyoShopOrders.goods_id].to_s
        text = item_id + sprintf(KyoShopLabels::STEPSLEFT, steps)
        KyoShopOrders.goods_id = item_id = nil
      end
    end
    if text.is_a?(String)
      text = text.gsub(/\\[Uu]/){$game_system.refill_items[item_id].sips.to_s}
    elsif text.is_a?(Integer)
      align = text
      text = item_id
    else
      text = item_id
    end
    if text != @text or align != @align
      self.contents.clear
      self.contents.font.color = normal_color
      self.contents.draw_text(4, 0, self.width - 40, 32, text, align)
      @text = text
      @align = align
      @actor = nil
    end
    self.visible = true
  end
end

class Window_Item
  alias kyon_discounts_win_item_up_help update_help
  def update_help
    KyoShopOrders.goods_id = self.item.id
    kyon_discounts_win_item_up_help
  end
end

class AppraiseItemWindow < Window_Selectable
  include WindowModule
  def initialize
    super(0, 64, 480, 320)
    @column_max = 1
    refresh
    self.index = 0
  end

  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for n in KyoShop::MYSTERIOUSITEMS
      next if $game_party.item_number(n) == 0
      @data << $data_items[n]
    end
    for i in KyoShop::MYSTERIOUSWEAPONS
      next if $game_party.weapon_number(i) == 0
      @data << $data_weapons[i]
    end
    for i in KyoShop::MYSTERIOUSARMORS
      next if $game_party.armor_number(i) == 0
      @data << $data_armors[i]
    end
    @item_max = @data.size
    return if @item_max == 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    @item_max.times{|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    c = self.contents
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    c.fill_rect(rect, Color.new(0, 0, 0, 0))
    bit = RPG::Cache.icon(item.icon_name)
    c.blt(x, y + 4, bit, Rect.new(0, 0, 24, 24), 255)
    c.draw_text(x + 28, y, 212, 32, item.name, 0)
    c.draw_text(x + 240, y, 16, 32, ":", 1)
    c.draw_text(x + 256, y, 24, 32, number.to_s, 2)
  end
  def item() @data[@index] end
  def empty?() @data.empty? end
end

class AppraiseInfoWindow < Window_Base
  def initialize(store_id)
    super(480, 128, 160, 256)
    @data = KyoShop::APPRAISALS[store_id]
    @labels = KyoShopLabels::APPRAISALLABELS.dup
    @currency = $data_system.words.gold
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end

  def refresh
    aw = width - 32
    contents.clear
    contents.font.color = system_color
    contents.draw_text(0, 0, aw, 24, @labels[0])
    contents.draw_text(0, 48, aw, 24, @labels[1])
    contents.draw_text(0, 24, aw, 24, @currency, 2)
    contents.draw_text(0, 72, aw, 24, @currency, 2)
    contents.font.color = normal_color
    contents.draw_text(0, 24, width - 48, 24, @data[:test_cost].to_s, 2)
    contents.draw_text(0, 72, width - 48, 24, @data[:cost].to_s, 2)
  end
end

class AppraiseResultWindow < Window_Base
  def initialize
    super(0, 384, 640, 96)
    @labels = KyoShopLabels::APPRAISALRESULTLABELS.dup
    @currency = $data_system.words.gold
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def refresh(item)
    contents.clear
    result = sprintf(@labels[0], item.name)
    cost = sprintf(@labels[1], item.price) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, cost)
  end
end

class Window_ShopCommand
  def initialize
    super(0, 64, 480, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    @item_max = 3
    @column_max = 3
    @commands = KyoShopLabels::BASIC.dup
    if KyoShop::APPRAISALS[$game_variables[KyoShop::STORECODEVARID]]
      @commands[0] = KyoShopLabels::MOREOPTIONS.dup
    end
    refresh
    self.index = 0
  end
end

class Window_ShopBuy
  attr_accessor :discount
  def initialize(shop_goods)
    super(0, 128, 368, 288)
    @shop_goods = shop_goods
    @discount = 0
    refresh
    self.index = 0
  end

  def deliver(goods)
    @shop_goods = goods
    if goods.size - 1 < @index
      @index = goods.size > 0 ? (@index + goods.size - 1) % goods.size : 0
      update_cursor_rect
    end
    refresh
    self.index = 0
  end

  def draw_item(index)
    item = @data[index]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    enough = (item.price <= $game_party.gold and number < 99)
    self.contents.font.color = enough ? normal_color : disabled_color
    y = index * 32
    rect = Rect.new(4, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    opacity = enough ? 255 : 128
    self.contents.blt(4, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(32, y, 212, 32, item.name, 0)
    price = item.price - item.price * @discount / 100
    self.contents.draw_text(244, y, 88, 32, price.to_s, 2)
  end
end

class Window_ShopPickUp < Window_ShopBuy
  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for good in @shop_goods
      new_item = case good[0]
      when 0 then $data_items[good[1]]
      when 1 then $data_weapons[good[1]]
      when 2 then $data_armors[good[1]]
      end
      @data << new_item if new_item
    end
    @item_max = @data.size
    return if @item_max == 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    (0...@item_max).each {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    qty, steps = @shop_goods[index][2..3]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    enough = (number + qty < 100 and steps <= $game_party.steps)
    self.contents.font.color = enough ? normal_color : disabled_color
    y = index * 32
    rect = Rect.new(4, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    opacity = enough ? 255 : 128
    self.contents.blt(4, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(32, y, 212, 32, item.name, 0)
    self.contents.draw_text(244, y, 88, 32, qty.to_s, 2)
  end
  undef discount, discount=
end

class Window_ShopNumber
  include WindowModule
  def initialize
    super(0, 128, 368, 288)
    self.contents = Bitmap.new(width - 32, height - 32)
    @item = nil
    @max = 1
    @price = 0
    @number = 1
    @multiplier = 1
  end

  def reset_multiplier
    @multiplier = 1
    @number = 1
    refresh
  end

  def set(item, max, price, percent=nil, multiplier=1)
    @item = item
    @max = max
    @price = price
    @number = 1
    @multiplier = multiplier
    @percent = percent
    refresh
  end

  def update
    super
    return unless self.active
    if Input.repeat?(Input::RIGHT) and @number < @max
      $game_system.se_play($data_system.cursor_se)
      @number += @multiplier
      refresh
    end
    if Input.repeat?(Input::LEFT) and @number > @multiplier
      $game_system.se_play($data_system.cursor_se)
      @number -= @multiplier
      refresh
    end
    if Input.repeat?(Input::UP) and @number < @max
      $game_system.se_play($data_system.cursor_se)
      @number = [@number + 10 * @multiplier, @max].min
      refresh
    end
    if Input.repeat?(Input::DOWN) and @number > @multiplier
      $game_system.se_play($data_system.cursor_se)
      @number = [@number - 10 * @multiplier, 1].max
      refresh
    end
  end

  def refresh
    self.contents.clear
    draw_item_name(@item, 4, 96)
    self.contents.font.color = normal_color
    if @multiplier == 1
      cx1, cx2, cx3, cw1, cw2 = [272, 308, 304, 24, 32]
    else
      cx1, cx2, cx3, cw1, cw2 = [260, 264, 272, 68, 64]
    end
    self.contents.draw_text(cx1, 96, 32, 32, "")
    self.contents.draw_text(cx2, 96, cw1, 32, @number.to_s, 2)
    self.cursor_rect.set(cx3, 96, cw2, 32)
    gold = $data_system.words.gold
    cx = contents.text_size(gold).width
    subtotal_price = @item.price * @number
    total_price = @price * @number
    labels = KyoShopLabels::PRICELABELS
    if total_price > subtotal_price and @multiplier < 2
      self.contents.font.color = system_color
      self.contents.draw_text(120, 128, 100, 32, labels[0], 2)
      self.contents.draw_text(332-cx, 128, cx, 32, gold, 2)
      self.contents.draw_text(80, 160, 140, 32, labels[1], 2)
      self.contents.draw_text(328-cx, 160, cx + 4, 32, '%', 2)
      self.contents.font.color = normal_color
      self.contents.draw_text(4, 128, 328-cx-2, 32, subtotal_price.to_s, 2)
      self.contents.draw_text(4, 160, 328-cx-2, 32, @percent.to_s, 2)
    end
    self.contents.draw_text(4, 192, 328-cx-2, 32, total_price.to_s, 2)
    self.contents.font.color = system_color
    self.contents.draw_text(120, 192, 100, 32, labels[2], 2)
    self.contents.draw_text(332-cx, 192, cx, 32, gold, 2)
  end
end

class Window_ShopBuyOptions < Window_Selectable
  def initialize
    commands = KyoShopLabels::BUYPLACEPICKUP.dup
    varid = $game_variables[KyoShop::STORECODEVARID]
    commands.pop unless KyoShop::INVESTSTOREIDS.include?(varid)
    super(214, 148, 212, commands.size * 32 + 32)
    @commands = commands
    @item_max = @commands.size
    self.contents = Bitmap.new(width - 32, @item_max * 32)
    refresh
    self.index = 0
  end

  def refresh
    self.contents.clear
    @item_max.times {|i| @commands[i]
    contents.draw_text(4, i * 32, 172, 32, @commands[i]) }
  end
end

class Window_ShopDiscountAlert < Window_Base
  def initialize
    super(0, 416, 368, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def set_text(text)
    self.contents.clear
    self.contents.draw_text(0, 0, width - 32, height - 32, text)
  end
end

class Window_ShopDiscountCoupon < Window_Selectable
  def initialize
    super(0, 128, 368, 288)
    self.index = 0
    refresh
  end

  def item() @data[@index] end

  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    dc_ids = $game_party.discounts.keys.sort
    dc_ids.each {|i| next if $game_party.discounts[i] == 0
      next if !$game_system.disc_store?(i) and !$game_system.excl_disc_store?(i)
      @data << $data_items[i] }
    KyoShop::COUPON_IDS.each {|i| next unless $game_party.item_number(i) > 0
      @data << $data_items[i] }
    @item_max = @data.size
    return if @item_max == 0
    self.index -= 1 if @index > @item_max - 1
    self.contents = Bitmap.new(width - 32, row_max * 32)
    (0...@item_max).each {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = $game_party.item_number(item.id)
    x = 4
    y = index * 32
    rect = Rect.new(x, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), 255)
    self.contents.draw_text(x + 28, y, 212, 32, item.name)
    self.contents.draw_text(x + 28, y, 244, 32, ': ' + number.to_s, 2)
  end

  def update_help
    KyoShopOrders.goods_id = self.item.id
    @help_window.set_text(self.item.description)
  end
end

class Window_ShopStatus
  alias kyon_discounts_win_shop_status_refresh refresh
  def refresh
    if @investment
      refresh_investment
      return
    end
    kyon_discounts_win_shop_status_refresh
  end

  def investment=(bool)
    @investment = bool
    refresh
  end

  def refresh_investment
    shares = $game_system.shop_shares[$game_variables[KyoShop::STORECODEVARID]]
    contents.font.color = system_color
    contents.draw_text(0, 0, 240, 32, KyoShopLabels::TOTALSHARES)
    contents.font.color = normal_color
    contents.draw_text(0, 0, 240, 32, shares.to_s, 2)
  end
end

class Interpreter
  alias kyon_discounts_inter_comm_302 command_302
  def command_302
    if $game_switches[KyoShop::GOODSSWITCHID]
      KyoShopOrders.store_event_id = @event_id
      $game_switches[KyoShop::GOODSSWITCHID] = false
      $game_system.shop_goods = [@parameters]
      loop do
        @index += 1
        if @list[@index].code == 605
          $game_system.shop_goods << @list[@index].parameters
        else
          return false
        end
      end
    end
    kyon_discounts_inter_comm_302
  end
end

class Scene_Shop
  alias kyon_discounts_scn_shop_up update
  def main
    start
    Graphics.transition
    while @keep_loop
      Graphics.update
      Input.update
      update
    end
    Graphics.freeze
    terminate
  end

  def start
    @keep_loop = true
    @stage = :main
    @shop_id = $game_variables[KyoShop::STORECODEVARID]
    @goods = $game_temp.shop_goods.dup
    @orders = $game_system.shop_goods.dup
    update_goods_orders_after_investment
    make_basic_windows
    @discount_window = Window_ShopDiscountCoupon.new
    @discount_window.disappear
    @discount_window.help_window = @help_window
    unless $game_system.shop_goods.empty?
      @order_window = Window_ShopBuy.new($game_system.shop_goods)
      @order_window.disappear
      @order_window.help_window = @help_window
      @option_window = Window_ShopBuyOptions.new
      @option_window.z += 200
      @option_window.disappear
    end
    if (@need_appraisal = KyoShop::APPRAISALS.keys.include?(@shop_id))
      @appraise_item_window = AppraiseItemWindow.new
      @appraise_item_window.visible = false
      @appraise_info_window = AppraiseInfoWindow.new(@shop_id)
      @appraise_info_window.visible = false
      options = KyoShopLabels::APPRAISALOPTIONS.dup
      @appraise_options = Window_Command.new(160, options)
      @appraise_options.disappear
      @appraise_options.x = 240
      @appraise_options.y = 200
      @result_info_window = AppraiseResultWindow.new
    else
      @option_window.disable_item(3)
    end
    @purchase_window = Window_ShopBuy.new($game_temp.shop_goods)
    @purchase_window.disappear
    @purchase_window.help_window = @help_window
    @pack_id = [$game_map.map_id, KyoShopOrders.store_event_id]
    goods = $game_system.placed_orders[@pack_id]
    goods ||= []
    @pickup_window = Window_ShopPickUp.new(goods)
    @pickup_window.disappear
    @pickup_window.help_window = @help_window
    @sell_window = Window_ShopSell.new
    @sell_window.disappear
    @sell_window.help_window = @help_window
    @number_window = Window_ShopNumber.new
    @number_window.disappear
    @status_window = Window_ShopStatus.new
    @status_window.visible = false
  end

  def update_goods_orders_after_investment
    gds = []
    orders = []
    stuff = $game_system.check_shares(@shop_id)
    return if stuff.empty?
    stuff.each {|b| gds += strings_goods_conversion(b[1..-1]) if b[0] == :goods
      orders += string_good_conversion(b[1..-1]) if b[0] == :orders }
    $game_system.shop_goods = (@orders + orders).sort.uniq
    $game_temp.shop_goods = (@goods + gds).sort.uniq
  end

  def strings_goods_conversion(strings)
    data = []
    strings.each {|string| data << retrieve_item(string) }
    data
  end

  def retrieve_item(string)
    case string[0,1]
    when 'i' then [0, string[1..-1].to_i]
    when 'w' then [1, string[1..-1].to_i]
    when 'a' then [2, string[1..-1].to_i]
    end
  end

  def make_basic_windows
    @help_window = Window_Help.new
    @command_window = Window_ShopCommand.new
    @gold_window = Window_Gold.new
    @gold_window.x = 480
    @gold_window.y = 64
    @dummy_window = Window_Base.new(0, 128, 640, 352)
    @question_window = Window_ShopDiscountAlert.new
    @question_window.visible = false
  end

  def terminate
    @help_window.dispose
    @command_window.dispose
    @gold_window.dispose
    @dummy_window.dispose
    @purchase_window.dispose
    @pickup_window.dispose
    @sell_window.dispose
    @number_window.dispose
    @status_window.dispose
    @question_window.dispose
    @discount_window.dispose
    $game_variables[KyoShop::STORECODEVARID] = 0
    if @need_appraisal
      @appraise_item_window.dispose
      @appraise_info_window.dispose
      @appraise_options.dispose
      @result_info_window.dispose
    end
    return if $game_system.shop_goods.empty?
    @order_window.dispose
    @option_window.dispose
    $game_system.shop_goods.clear
    KyoShopOrders.commissions.clear
    KyoShopOrders.steps.clear
    KyoShopOrders.store_event_id = nil
    @stage = nil
  end

  def update_discount_message
    cd = $game_party.check_discounts
    text = cd ? KyoShopLabels::SOMEDISCOUNTS : KyoShopLabels::NODISCOUNTS
    @question_window.set_text(text)
  end

  def update
    @help_window.update
    @gold_window.update
    @dummy_window.update
    @sell_window.update
    @status_window.update
    case @stage
    when :main then update_command
    when :option then update_option
    when :purchase then update_purchase
    when :place then update_place_order
    when :pickup then update_pickup_order
    when :discount then update_discount
    when :appraise then update_appraisal
    when :appraise_option then update_appraisal_option
    when :sell then update_sell
    when :number then update_number
    end
  end

  def update_command
    @command_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Map.new
      return @keep_loop = nil
    elsif Input.trigger?(Input::C)
      case @command_window.index
      when 0 # buy
        $game_system.se_play($data_system.decision_se)
        @command_window.active = false
        if $game_system.shop_goods.empty?
          @discount = 0
          @dummy_window.visible = false
          @question_window.visible = true
          @status_window.visible = true
          @purchase_window.appear
          @purchase_window.refresh
          update_discount_message
          return @stage = :purchase
        else
          @option_window.appear
          return @stage = :option
        end
      when 1 # sell
        $game_system.se_play($data_system.decision_se)
        @command_window.active = false
        @dummy_window.visible = false
        @sell_window.appear
        @sell_window.refresh
        return
      when 2 # quit
        $game_system.se_play($data_system.decision_se)
        $scene = Scene_Map.new
        @keep_loop = nil
      end
    end
  end

  def update_option
    @option_window.update
    @order_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @option_window.disappear
      @status_window.visible = false
      @command_window.active = true
      @dummy_window.visible = true
      return @stage = :main
    elsif Input.trigger?(Input::C)
      shares = $game_system.shop_shares[@shop_id]
      inv_max, inv_price = KyoShop::SHARESMAXMIN
      pos = @option_window.index
      if pos == 3 and !@need_appraisal
        return $game_system.se_play($data_system.buzzer_se)
      end
      if pos == 4 and inv_max == shares
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      @dummy_window.visible = false
      @option_window.disappear
      @question_window.visible = true
      @status_window.visible = true
      case pos
      when 0 # buy
        @discount = 0
        @purchase_window.discount = 0
        disc = $game_system.check_shares(@shop_id)
        disc.each {|b| @purchase_window.discount += b[1] if b[0] == :discount }
        @status_window.item = @purchase_window.item
        @purchase_window.refresh
        @purchase_window.appear
        update_discount_message
        return @stage = :purchase
      when 1 # place order
        @status_window.item = @order_window.item
        @order_window.appear
        @order_window.refresh
        @question_window.set_text(KyoShopLabels::PLACEORDER)
        return @stage = :place
      when 2 # pick up stuff
        @status_window.item = @pickup_window.item
        @pickup_window.appear
        @pickup_window.refresh
        @question_window.set_text(KyoShopLabels::PICKUPORDER)
        return @stage = :pickup
      when 3 # appraisal
        @appraise_item_window.appear
        @appraise_info_window.visible = true
        @result_info_window.visible = true
        @dummy_window.visible = false
        @command_window.visible = false
        @number_window.visible = false
        @status_window.visible = false
        @help_window.set_text(KyoShopLabels::APPRAISALMENULABEL)
        return @stage = :appraise
      when 4 # investments
        @status_window.investment = @investment = true
        inv_max = [inv_max - shares, $game_party.gold / inv_price].min
        fake_item = RPG::Item.new
        fake_item.name = KyoShopLabels::SHARES
        @price = inv_price
        @number_window.set(fake_item, inv_max, inv_price, nil, 10)
        @number_window.appear
        @question_window.set_text(KyoShopLabels::INVESTMENT)
        @stage = :number
      end
    end
  end

  def update_purchase
    @purchase_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      if $game_system.shop_goods.empty?
        @command_window.active = true
        @stage = :main
      else
        @option_window.appear
        @stage = :option
      end
      @discount = 0
      @purchase_window.discount = 0
      @dummy_window.visible = true
      @purchase_window.disappear
      @question_window.visible = false
      @status_window.visible = false
      @status_window.item = nil
      @help_window.set_text("")
      return
    end
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @purchase_window.item
      return
    end
    if Input.trigger?(KyoShop::DISCOUNTBUTTON)
      unless $game_party.check_discounts
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      @purchase_window.disappear
      @discount_window.refresh
      @discount_window.appear
      @question_window.set_text(KyoShopLabels::SELECTDISCOUNT)
      return @stage = :discount
    elsif Input.trigger?(Input::C)
      discount = @purchase_window.discount
      percent = KyoShop.current_price_max
      @item = @purchase_window.item
      @price = @item.price + @item.price * percent / 100
      @price -= @item.price * discount / 100 if discount > 0
      if @item == nil or @price > $game_party.gold
        return $game_system.se_play($data_system.buzzer_se)
      end
      shop_max = KyoShop.current_item_max
      if (number = check_number) == shop_max
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      max = @price == 0 ? shop_max : $game_party.gold / @price
      max = [max, shop_max - number].min
      @purchase_window.disappear
      @number_window.set(@item, max, @price)
      @number_window.appear
      @last_stage = @stage
      @stage = :number
    end
  end

  def update_place_order
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @option_window.appear
      @dummy_window.visible = true
      @order_window.disappear
      @question_window.visible = false
      @status_window.visible = false
      @status_window.item = nil
      @help_window.set_text("")
      return @stage = :option
    end
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @order_window.item
      return
    end
    if Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      @item = @order_window.item
      @price = @item.price
      percent = KyoShopOrders.commissions[@order_window.index]
      percent += KyoShop.current_price_max
      @price += percent * @item.price / 100 if percent > 0
      if @item == nil or @price > $game_party.gold
        return $game_system.se_play($data_system.buzzer_se)
      end
      number = check_number
      shop_max = KyoShop.current_item_max
      if number == shop_max
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      max = @price == 0 ? shop_max : $game_party.gold / @price
      max = [max, shop_max - number].min
      @order_window.disappear
      @place_order = true
      @number_window.set(@item, max, @price, percent)
      @number_window.appear
      @question_window.set_text(KyoShopLabels::FEESAPPLY)
      @last_stage = @stage
      @stage = :number
    end
  end

  def update_pickup_order
    @pickup_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @dummy_window.visible = true
      @question_window.visible = false
      @status_window.visible = false
      @pickup_window.disappear
      @option_window.appear
      return @stage = :option
    end
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @pickup_window.item
      return
    end
    if Input.trigger?(Input::C)
      current_item = @pickup_window.item
      goods = $game_system.placed_orders[@pack_id]
      unless goods
        return $game_system.se_play($data_system.buzzer_se)
      end
      goods = goods[@pickup_window.index]
      unless current_item and goods[3] <= $game_party.steps
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      number = goods[2]
      case current_item
      when RPG::Item then $game_party.gain_item(current_item.id, number)
      when RPG::Weapon then $game_party.gain_weapon(current_item.id, number)
      when RPG::Armor then $game_party.gain_armor(current_item.id, number)
      end
      $game_system.placed_orders[@pack_id].delete_at(@pickup_window.index)
      @pickup_window.deliver($game_system.placed_orders[@pack_id])
    end
  end

  def update_discount
    @discount_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @discount_window.disappear
      @purchase_window.appear
      return @stage = :purchase
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      @coupons_allowed = KyoShop::COUPON_IDS.include?(@discount_window.item.id)
      @purchase_window.discount -= @discount
      @discount = @discount_window.item.price
      @discount_window.disappear
      @purchase_window.appear
      discount = @purchase_window.discount += @discount
      @purchase_window.refresh
      text = sprintf(KyoShopLabels::APPLYDISCOUNT, discount)
      @question_window.set_text(text)
      @stage = :purchase
    end
  end

  def update_appraisal
    @appraise_item_window.update
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @appraise_info_window.refresh
      return
    end
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @appraise_item_window.disappear
      @appraise_info_window.visible = false
      @result_info_window.visible = false
      @result_info_window.contents.clear
      @appraise_options.disappear
      @dummy_window.visible = true
      @command_window.visible = true
      @number_window.visible = true
      @status_window.visible = true
      @option_window.appear
      @help_window.set_text("")
      return @stage = :option
    elsif Input.trigger?(Input::C)
      if @appraise_item_window.empty?
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      @appraise_options.appear
      @stage = :appraise_option
    end
  end

  def update_appraisal_option
    @appraise_options.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @appraise_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      data = KyoShop::APPRAISALS[@shop_id]
      price = case @appraise_options.index
      when 0 then data[:test_cost]
      when 1 then data[:cost]
      when 2 then -10
      end
      if price == -10 or $game_party.gold < price
        $game_system.se_play($data_system.buzzer_se)
        @appraise_options.disappear
        return @stage = :appraise
      end
      $game_system.se_play($data_system.decision_se)
      item = @appraise_item_window.item
      $game_party.lose_item(item.id, 1)
      $game_party.lose_gold(price)
      if rand(100) < data[:rate]
        goods = data[:goods]
        kind, id = retrieve_item(goods[rand(goods.size)])
      else
        kind, id = retrieve_item(data[:default])
      end
      item = case kind
      when 0 then $data_items[id]
      when 1 then $data_weapons[id]
      when 2 then $data_armors[id]
      end
      @result_info_window.refresh(item)
      @appraise_item_window.refresh
      @gold_window.refresh
      @appraise_options.disappear
      @stage = :appraise
    end
  end

  def check_number
    return number = case @item
    when RPG::Item then $game_party.item_number(@item.id)
    when RPG::Weapon then $game_party.weapon_number(@item.id)
    when RPG::Armor then $game_party.armor_number(@item.id)
    end
  end

  def update_number
    @number_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @number_window.disappear
      @number_window.reset_multiplier
      case @command_window.index
      when 0 # buy or place order
        if @place_order
          @place_order = nil
          @order_window.appear
          @question_window.set_text(KyoShopLabels::PLACEORDER)
        elsif @investment
          @investment = nil
          @status_window.investment = nil
          @option_window.appear
          @question_window.visible = false
          @status_window.visible = false
          @dummy_window.visible = true
        else
          @purchase_window.appear
          discount = @purchase_window.discount
          if discount == 0
            update_discount_message
          else
            text = sprintf(KyoShopLabels::APPLYDISCOUNT, discount) + "%"
            @question_window.set_text(text)
          end
        end
      when 1 # sell
        update_discount_message
        @sell_window.appear
        @status_window.visible = false
      end
      @stage = @last_stage
      return @last_stage = nil
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.shop_se)
      @number_window.disappear
      case @command_window.index
      when 0  # buy
        $game_party.lose_gold(@number_window.number * @price)
        number = @number_window.number
        if @place_order
          update_number_place_order(number)
        elsif @investment
          update_number_investment(number)
        else
          update_number_purchase(number)
        end
        return
      when 1  # sell
        number = @number_window.number
        $game_party.gain_gold(number * (@item.price / 2))
        case @item
        when RPG::Item then   $game_party.lose_item(@item.id, number)
        when RPG::Weapon then $game_party.lose_weapon(@item.id, number)
        when RPG::Armor then  $game_party.lose_armor(@item.id, number)
        end
        @gold_window.refresh
        @sell_window.refresh
        @status_window.refresh
        @sell_window.appear
        @status_window.visible = false
        @stage = @last_stage
        return @last_stage = nil
      end
    end
  end

  def update_number_place_order(number)
    steps = $game_party.steps + KyoShopOrders.steps[@order_window.index]
    order = [nil, @item.id, number, steps]
    order[0] = case @item
    when RPG::Item then 0
    when RPG::Weapon then 1
    when RPG::Armor then 2
    end
    $game_system.placed_orders[@pack_id] ||= []
    $game_system.placed_orders[@pack_id] << order
    @pickup_window.deliver($game_system.placed_orders[@pack_id])
    @gold_window.refresh
    @status_window.refresh
    @place_order = nil
    @order_window.refresh
    @order_window.appear
    @question_window.set_text(KyoShopLabels::PLACEORDER)
    @stage = :place
  end

  def update_number_investment(number)
    @investment = nil
    @status_window.investment = nil
    $game_system.shop_shares[@shop_id] += number
    update_goods_orders_after_investment
    @order_window.deliver($game_system.shop_goods)
    @purchase_window.deliver($game_temp.shop_goods)
    @gold_window.refresh
    @question_window.visible = false
    @status_window.visible = false
    @dummy_window.visible = true
    @number_window.reset_multiplier
    @number_window.disappear
    @option_window.appear
    @stage = :option
  end

  def update_number_purchase(number)
    case @item
    when RPG::Item then $game_party.gain_item(@item.id, number)
    when RPG::Weapon then $game_party.gain_weapon(@item.id, number)
    when RPG::Armor then $game_party.gain_armor(@item.id, number)
    end
    if @coupons_allowed
      @coupons_allowed = nil
      $game_party.lose_item(@discount_window.item.id, 1)
      update_discount_message
      @discount_window.refresh
      @purchase_window.discount = 0
      @discount = 0
    end
    @gold_window.refresh
    @status_window.refresh
    @purchase_window.refresh
    @purchase_window.appear
    @stage = :purchase
  end
end



RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-14-2019

Here I come again! Nope, I ain't singing here! Laughing + Tongue sticking out

A while ago I finished a new release of KyoDiscounts XP where game developers will now feel free to include extra features like haggling! The benefits would be that it would count as a favor so the storekeeper alias appraiser might be able to offer extra goods after finishing his or her appraisal. Nope, don't worry, pals! Laughing They won't get more than a single good at a time. The difference would be that the player would be able to get a chance to get a good that wasn't available before doing him or her a favor...or series of favors. If the appraisal results in a great finding that captivates the appraiser, he or she will make you an offer and even a second and final offer if you allow that!

Happy Game Testing!? Laughing

Edit: I have finished implementing favors so now the shopkeeper alias appraiser should recall how many times you have brought and sold interesting items to him or her.

Code:
# * KyoDiscounts XP
#   Scripter : Kyonides-Arkanthes
#   v1.5.0 - 2019-01-14

#   Whenever you obtain a discount card, such discount will be applied to all
#   of your purchases if you have picked a card till it expires after a certain
#   number of steps. Additional steps will be quickly added to your current card
#   whenever you purchase any additional card of the same kind.

#   One coupon will be spent every single time you purchase any specific item,
#   you will need another one to purchase a different item later on.
#   The discount card or coupon price is used to calculate the corresponding
#   discount on every single purchase the player makes with it.

#   Place this script below KItemRefill XP or KyoScriptPack Item XP if you
#   included any of those scripts in your current game project.

#   Now you can also setup exclusive store discount cards as well. Just keep in
#   mind that you will need to setup the in game variable you picked so it will
#   be able to store the Exclusive Store Code (an Integer) before you can add
#   the shop event command. Common stores don't need any Store Code at all.

#   Besides the player can also place orders to get an item that is supposed to
#   be found at another store only. The player will be charged an extra fee, but
#   he or she won't need to go back to another store. The player would only need
#   to keep walking for a while before the goods are available at the store.
#   Now the required steps for each placed order will be automatically increased
#   between 0% and 50%, making it look a bit random but also kind of realistic.

# * Unknown Item or Weapon or Armor Appraisals *

#   Use the Game Variable defined in the STORECODEVARID Constant to store the
#   Shop ID that will include the appraisal service.
#   Use the MYSTERIOUS series of Arrays to include as many IDs of unknown items
#   or weapons or armors that will serve as fillers till they get replaced by
#   the actual goods they represent.
#   Follow the Instructions included in the APPRAISALS Hash to define all
#   conditions that will affect an appraiser's task of identifying the item.

#   Script Calls   #

#   $game_party.discount_cards_expire
#      Makes all Discount Cards expire as part of the game's plot.

#   $game_party.disc_card_expire(Card_ID)
#      Makes an specific Discount Card expire as part of the game's plot.

#   KyoShopOrders << [Percent1, Percent2, etc.]
#      Defines a Commission percent for every Item in the Place Order List.

#   KyoShopOrders.steps = [Steps1, Steps2, etc.]
#   KyoShopOrders.steps += [Steps5, Steps6, etc.]
#      Defines Steps required by every Order in the Place Order List.
#      The 2nd call will be required only if you couldn't include all steps.

#   KyoShop.scarcity_lvl = 0 or higher
#     Define all prices and maximum number of units per shop item.
#     0 means no scarcity, 1 or higher reflects how severe it is.
#     You also have to configure the @scarce_limits hash in order to predefine
#     :price and :max per scarcity level. The maximum scarcity level depends on
#     how many values you entered in both :price and :max arrays.
#     In few words, you define the maximum scarcity level ever possible!

module KyoShop
  # Maximum number of units for each shop item
  NUMBERMAX = 99
  # Button that will open the Discount window while on the shop menu
  DISCOUNTBUTTON = Input::A
  # Add Discount Card Object IDs
  DISCOUNT_IDS = [33, 34]
  # Add Discount Coupon Object IDs
  COUPON_IDS = [36, 37]
  # Maximum Steps before Discount Card expires : ID => Steps
  STEPS = { 33 => 500, 34 => 300, 35 => 150 }
  # Exclusive Stores In Game Variable ID
  STORECODEVARID = 1
  # Exclusive Stores List : Object ID => Exclusive Store Code
  EXCLUSIVESTORES = { 35 => 102 }
  # Switch ID : deactivates Store to add Goods found elsewhere
  GOODSSWITCHID = 1
  # Store IDs for stores where you have invested some gold
  INVESTSTOREIDS = [101]
  # Maximum Number of Shares & Share Price
  SHARESMAXMIN = [10000, 100]
  INVESTMENTS = {} # Store Investments - Do Not Edit This Line
  INVESTMENTS.default = {} # Do Not Edit This Line
  # Available Improvements #
  # :discount : [:discount, 25]
  # :goods    : [:goods, 'i10', 'w4', 'a6']
  # :orders   : [:orders, 'i11', 'w5', 'a7']
  # [Store ID] = { Shares => Prize, Shares => Another Prize, etc. }
  INVESTMENTS[101] = { 50 => [:goods,'i10','w5','a6'], 100 => [:discount,10] }
  APPRAISALS = {} # Do Not Edit This Line!
  # [Store ID] = { appraisal cost => $, estimate cost => $, success rate => %,
  # times you can help the a. => 0, bad result => "i1", goods => [item4, etc.] }
  APPRAISALS[101] = { :cost => 150, :test_cost => 75, :rate => 10,
      :default => 'i1', :help_limit => 5, :haggle => true,
      :target => { 'i9' => 1, 'i10' => 2 },
      :goods => ['i2','i3','i9','i10'], :extras => ['i11'] }
  # Add Item IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSITEMS = []
  # Add Weapon IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSWEAPONS = []
  # Add Armor IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSARMORS = []
  @scarce_limits = {
    :price  => [0, 25, 50, 100, 250, 350, 500, 650, 800],
    :max => [NUMBERMAX, NUMBERMAX - 10, NUMBERMAX - 25, NUMBERMAX - 35,
        NUMBERMAX - 50, NUMBERMAX - 65, NUMBERMAX - 80, NUMBERMAX - 90, 1]
    #:item => [1, 2, 3, 4, 5, 6],
    #:weapon => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
    #:armor => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
  }
  @scarce_lvl = 0 # Initial Level
  def self.current_item_max() @scarce_limits[:max][@scarce_lvl] end
  def self.current_price_max() @scarce_limits[:price][@scarce_lvl] end
  def self.scarcity_limits() @scarce_limits end
  def self.scarcity_lvl() @scarce_lvl end
  def self.scarcity_lvl=(lvl) @scarce_lvl = lvl end
end

module KyoShopLabels
  # Basic Shop Command Labels
  BASIC = ["Buy", "Sell", "Exit"]
  MOREOPTIONS = "Options"
  # Buy Stuff & Place Order & Pick Up Items Label
  BUYPLACEPICKUP = ['Buy Items', 'Place Order', 'Pick Up Items',
                    'Appraise', 'Invest']
  # Subtotal, Commission Percent and Total Amount
  PRICELABELS = ['Subtotal', 'Commission %', 'Total']
  # Place an Order Label
  PLACEORDER = 'Do you wish to place an order?'
  # Pick Up Order Label
  PICKUPORDER = 'Do you want to pick up an order?'
  # No Order Found Label
  NOORDERFOUND = 'There is nothing left, boss!'
  # Available Discounts Label
  SOMEDISCOUNTS = 'Press A to get a discount'
  # No Discount Available Label
  NODISCOUNTS = 'No Discount Available'
  # Select a Discount Card or Coupon Label
  SELECTDISCOUNT = 'Choose a Card or Coupon'
  # Apply Discount Label
  APPLYDISCOUNT = "Discount Applied %s%"
  # Warning about Extra Fees for Placing Orders
  FEESAPPLY = 'Extra Fees Apply'
  # Discount Card's Steps Left Label
  STEPSLEFT = " %s steps left."
  # Investment Label...
  INVESTMENT = 'Want to invest in this store?'
  # Share Number Label
  SHARES = 'Share Number'
  # Adquired or Purchased Shares Label
  TOTALSHARES = 'Total Shares'
  # Pick Item to be Appraised Label
  APPRAISALMENULABEL = "Appraisal Menu"
  # Appraisal Window Labels
  APPRAISALLABELS = ["Quick Test Cost", "Normal Cost"]
  # Appraisal Options Labels
  APPRAISALOPTIONS = ["Quick Test", "Detailed Test", "Cancel"]
  # Purchase Offer and Haggle Labels
  APPRAISALHAGGLEOPTIONS = ["Accept", "Haggle", "Decline"]
  # Appraisal End Result Labels
  APPRAISALRESULTLABELS = [
    "The item at hand is nothing else but... %s",
    "I think it might be worth some... %s",
    "I've been searching for some %s!",
    "Now I want to make a deal.",
    "What if I make a better offer?",
    "Would you accept some %s?"
  ]
end
# DO NOT EDIT ANYTHING ELSE #
module KyoShopOrders
  @commissions = []
  @steps = []
  class << self
    attr_accessor :store_event_id, :goods_id
    attr_reader :steps, :commissions
    def steps=(val) @steps = val.map {|n| n + rand((n / 2) + 2) } end
    def <<(val)
      @commissions += val
      @commissions = @commissions.flatten
    end
  end
end

module WindowModule
  def appear
    self.active = true
    self.visible = true
  end

  def disappear
    self.active = false
    self.visible = false
  end
end

class Game_System
  attr_accessor :shop_goods
  attr_reader :placed_orders, :shop_shares, :shop_favors
  alias kyon_discounts_gm_sys_init initialize
  def initialize
    @shop_goods = []
    @placed_orders = {}
    @shop_shares = {}
    @shop_favors = {}
    @placed_orders.default = []
    @shop_shares.default = 0
    @shop_favors.default = 0
    kyon_discounts_gm_sys_init
  end

  def disc_store?(disc_id) !KyoShop::EXCLUSIVESTORES[disc_id] end

  def excl_disc_store?(disc_id)
    exclusive = KyoShop::EXCLUSIVESTORES[disc_id]
    $game_variables[KyoShop::STORECODEVARID] == exclusive
  end

  def check_shares(shop_id)
    results = []
    shares = @shop_shares[shop_id]
    investments = KyoShop::INVESTMENTS[shop_id]
    limits = KyoShop::INVESTMENTS[shop_id].keys.sort
    results = investments.select{|limit| shares >= limit[0] }.map {|r| r[1] }
  end
end

class Game_Party
  attr_reader :discounts
  alias kyon_discounts_gm_party_init initialize
  alias kyon_discounts_gm_party_gain_item gain_item
  def initialize
    @discounts = {}
    kyon_discounts_gm_party_init
  end

  def gain_item(item_id, n)
    kyon_discounts_gm_party_gain_item(item_id, n)
    return if item_id == 0 or n == 0
    return unless KyoShop::DISCOUNT_IDS.include?(item_id)
    if @discounts[item_id]
      @discounts[item_id] += KyoShop::STEPS[item_id]
      @items[item_id] = 1
    else
      @discounts[item_id] = KyoShop::STEPS[item_id]
    end
  end

  def check_discounts
    unless @discounts.empty?
      for did in KyoShop::DISCOUNT_IDS
        next unless @discounts[did] and @discounts[did] > 0
        return true if $game_system.disc_store?(did)
        return true if $game_system.excl_disc_store?(did)
      end
    end
    for cid in KyoShop::COUPON_IDS
      next unless item_number(cid) > 0
      return true if $game_system.disc_store?(cid)
      return true if $game_system.excl_disc_store?(cid)
    end
    return false
  end

  def decrease_discounts
    KyoShop::DISCOUNT_IDS.each {|n| next unless @discounts[n]
      @discounts[n] -= 1 if @discounts[n] > 0 }
  end

  def discount_cards_expire
    KyoShop::DISCOUNT_IDS.each {|n| @discounts[n] = 0 if @discounts[n] }
  end

  def disc_card_expire(dc_id) @discounts[dc_id] = 0 end
end

class Game_Player
  alias kyon_discounts_coupons_gm_player_increase_steps increase_steps
  def increase_steps
    kyon_discounts_coupons_gm_player_increase_steps
    $game_party.decrease_discounts
  end
end

class Window_Selectable
  include WindowModule
end

class Window_Help
  def set_text(item_id, text=nil, align=0)
    if item_id.is_a?(String)
      if KyoShop::DISCOUNT_IDS.include?(KyoShopOrders.goods_id)
        steps = $game_party.discounts[KyoShopOrders.goods_id].to_s
        text = item_id + sprintf(KyoShopLabels::STEPSLEFT, steps)
        KyoShopOrders.goods_id = item_id = nil
      end
    end
    if text.is_a?(String)
      text = text.gsub(/\\[Uu]/){$game_system.refill_items[item_id].sips.to_s}
    elsif text.is_a?(Integer)
      align = text
      text = item_id
    else
      text = item_id
    end
    if text != @text or align != @align
      self.contents.clear
      self.contents.font.color = normal_color
      self.contents.draw_text(4, 0, self.width - 40, 32, text, align)
      @text = text
      @align = align
      @actor = nil
    end
    self.visible = true
  end
end

class Window_Item
  alias kyon_discounts_win_item_up_help update_help
  def update_help
    KyoShopOrders.goods_id = self.item.id
    kyon_discounts_win_item_up_help
  end
end

class AppraiseItemWindow < Window_Selectable
  def initialize
    super(0, 64, 480, 320)
    @column_max = 1
    refresh
    self.index = 0
  end

  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for n in KyoShop::MYSTERIOUSITEMS
      next if $game_party.item_number(n) == 0
      @data << $data_items[n]
    end
    for i in KyoShop::MYSTERIOUSWEAPONS
      next if $game_party.weapon_number(i) == 0
      @data << $data_weapons[i]
    end
    for i in KyoShop::MYSTERIOUSARMORS
      next if $game_party.armor_number(i) == 0
      @data << $data_armors[i]
    end
    @item_max = @data.size
    return if @item_max == 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    @item_max.times{|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    c = self.contents
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    c.fill_rect(rect, Color.new(0, 0, 0, 0))
    bit = RPG::Cache.icon(item.icon_name)
    c.blt(x, y + 4, bit, Rect.new(0, 0, 24, 24), 255)
    c.draw_text(x + 28, y, 212, 32, item.name, 0)
    c.draw_text(x + 240, y, 16, 32, ":", 1)
    c.draw_text(x + 256, y, 24, 32, number.to_s, 2)
  end
  def item() @data[@index] end
  def empty?() @data.empty? end
end

class AppraiseInfoWindow < Window_Base
  def initialize(store_id)
    super(480, 128, 160, 256)
    @data = KyoShop::APPRAISALS[store_id]
    @labels = KyoShopLabels::APPRAISALLABELS.dup
    @currency = $data_system.words.gold
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end

  def refresh
    aw = width - 32
    contents.clear
    contents.font.color = system_color
    contents.draw_text(0, 0, aw, 24, @labels[0])
    contents.draw_text(0, 48, aw, 24, @labels[1])
    contents.draw_text(0, 24, aw, 24, @currency, 2)
    contents.draw_text(0, 72, aw, 24, @currency, 2)
    contents.font.color = normal_color
    contents.draw_text(0, 24, width - 48, 24, @data[:test_cost].to_s, 2)
    contents.draw_text(0, 72, width - 48, 24, @data[:cost].to_s, 2)
  end
end

class AppraiseResultWindow < Window_Base
  def initialize
    super(0, 384, 640, 96)
    @labels = KyoShopLabels::APPRAISALRESULTLABELS.dup
    @currency = $data_system.words.gold
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def refresh(item)
    contents.clear
    result = sprintf(@labels[0], item.name)
    cost = sprintf(@labels[1], item.price) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, cost)
  end

  def ask_favor(item)
    contents.clear
    result = sprintf(@labels[2], item.name)
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, @labels[3])
  end

  def make_offer(overprice)
    contents.clear
    result = sprintf(@labels[5], overprice) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, @labels[4])
    contents.draw_text(0, 24, width - 32, 24, result)
  end
end

class Window_ShopCommand
  def initialize
    super(0, 64, 480, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
    @item_max = 3
    @column_max = 3
    @commands = KyoShopLabels::BASIC.dup
    if KyoShop::APPRAISALS[$game_variables[KyoShop::STORECODEVARID]]
      @commands[0] = KyoShopLabels::MOREOPTIONS.dup
    end
    refresh
    self.index = 0
  end
end

class Window_ShopBuy
  attr_accessor :discount
  def initialize(shop_goods)
    super(0, 128, 368, 288)
    @shop_goods = shop_goods
    @discount = 0
    refresh
    self.index = 0
  end

  def deliver(goods)
    @shop_goods = goods
    if goods.size - 1 < @index
      @index = goods.size > 0 ? (@index + goods.size - 1) % goods.size : 0
      update_cursor_rect
    end
    refresh
    self.index = 0
  end

  def draw_item(index)
    item = @data[index]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    enough = (item.price <= $game_party.gold and number < 99)
    self.contents.font.color = enough ? normal_color : disabled_color
    y = index * 32
    rect = Rect.new(4, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    opacity = enough ? 255 : 128
    self.contents.blt(4, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(32, y, 212, 32, item.name, 0)
    price = item.price - item.price * @discount / 100
    self.contents.draw_text(244, y, 88, 32, price.to_s, 2)
  end
end

class Window_ShopPickUp < Window_ShopBuy
  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    for good in @shop_goods
      new_item = case good[0]
      when 0 then $data_items[good[1]]
      when 1 then $data_weapons[good[1]]
      when 2 then $data_armors[good[1]]
      end
      @data << new_item if new_item
    end
    @item_max = @data.size
    return if @item_max == 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    (0...@item_max).each {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    qty, steps = @shop_goods[index][2..3]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    enough = (number + qty < 100 and steps <= $game_party.steps)
    self.contents.font.color = enough ? normal_color : disabled_color
    y = index * 32
    rect = Rect.new(4, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    opacity = enough ? 255 : 128
    self.contents.blt(4, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)
    self.contents.draw_text(32, y, 212, 32, item.name, 0)
    self.contents.draw_text(244, y, 88, 32, qty.to_s, 2)
  end
  undef discount, discount=
end

class Window_ShopNumber
  include WindowModule
  def initialize
    super(0, 128, 368, 288)
    self.contents = Bitmap.new(width - 32, height - 32)
    @item = nil
    @max = 1
    @price = 0
    @number = 1
    @multiplier = 1
  end

  def reset_multiplier
    @multiplier = 1
    @number = 1
    refresh
  end

  def set(item, max, price, percent=nil, multiplier=1)
    @item = item
    @max = max
    @price = price
    @number = 1
    @multiplier = multiplier
    @percent = percent
    refresh
  end

  def update
    super
    return unless self.active
    if Input.repeat?(Input::RIGHT) and @number < @max
      $game_system.se_play($data_system.cursor_se)
      @number += @multiplier
      refresh
    end
    if Input.repeat?(Input::LEFT) and @number > @multiplier
      $game_system.se_play($data_system.cursor_se)
      @number -= @multiplier
      refresh
    end
    if Input.repeat?(Input::UP) and @number < @max
      $game_system.se_play($data_system.cursor_se)
      @number = [@number + 10 * @multiplier, @max].min
      refresh
    end
    if Input.repeat?(Input::DOWN) and @number > @multiplier
      $game_system.se_play($data_system.cursor_se)
      @number = [@number - 10 * @multiplier, 1].max
      refresh
    end
  end

  def refresh
    self.contents.clear
    draw_item_name(@item, 4, 96)
    self.contents.font.color = normal_color
    if @multiplier == 1
      cx1, cx2, cx3, cw1, cw2 = [272, 308, 304, 24, 32]
    else
      cx1, cx2, cx3, cw1, cw2 = [260, 264, 272, 68, 64]
    end
    self.contents.draw_text(cx1, 96, 32, 32, "")
    self.contents.draw_text(cx2, 96, cw1, 32, @number.to_s, 2)
    self.cursor_rect.set(cx3, 96, cw2, 32)
    gold = $data_system.words.gold
    cx = contents.text_size(gold).width
    subtotal_price = @item.price * @number
    total_price = @price * @number
    labels = KyoShopLabels::PRICELABELS
    if total_price > subtotal_price and @multiplier < 2
      self.contents.font.color = system_color
      self.contents.draw_text(120, 128, 100, 32, labels[0], 2)
      self.contents.draw_text(332-cx, 128, cx, 32, gold, 2)
      self.contents.draw_text(80, 160, 140, 32, labels[1], 2)
      self.contents.draw_text(328-cx, 160, cx + 4, 32, '%', 2)
      self.contents.font.color = normal_color
      self.contents.draw_text(4, 128, 328-cx-2, 32, subtotal_price.to_s, 2)
      self.contents.draw_text(4, 160, 328-cx-2, 32, @percent.to_s, 2)
    end
    self.contents.draw_text(4, 192, 328-cx-2, 32, total_price.to_s, 2)
    self.contents.font.color = system_color
    self.contents.draw_text(120, 192, 100, 32, labels[2], 2)
    self.contents.draw_text(332-cx, 192, cx, 32, gold, 2)
  end
end

class Window_ShopBuyOptions < Window_Selectable
  def initialize
    commands = KyoShopLabels::BUYPLACEPICKUP.dup
    varid = $game_variables[KyoShop::STORECODEVARID]
    commands.pop unless KyoShop::INVESTSTOREIDS.include?(varid)
    super(214, 148, 212, commands.size * 32 + 32)
    @commands = commands
    @item_max = @commands.size
    self.contents = Bitmap.new(width - 32, @item_max * 32)
    refresh
    self.index = 0
  end

  def refresh
    self.contents.clear
    @item_max.times {|i| @commands[i]
    contents.draw_text(4, i * 32, 172, 32, @commands[i]) }
  end
end

class Window_ShopDiscountAlert < Window_Base
  def initialize
    super(0, 416, 368, 64)
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def set_text(text)
    self.contents.clear
    self.contents.draw_text(0, 0, width - 32, height - 32, text)
  end
end

class Window_ShopDiscountCoupon < Window_Selectable
  def initialize
    super(0, 128, 368, 288)
    self.index = 0
    refresh
  end

  def item() @data[@index] end

  def refresh
    if self.contents != nil
      self.contents.dispose
      self.contents = nil
    end
    @data = []
    dc_ids = $game_party.discounts.keys.sort
    dc_ids.each {|i| next if $game_party.discounts[i] == 0
      next if !$game_system.disc_store?(i) and !$game_system.excl_disc_store?(i)
      @data << $data_items[i] }
    KyoShop::COUPON_IDS.each {|i| next unless $game_party.item_number(i) > 0
      @data << $data_items[i] }
    @item_max = @data.size
    return if @item_max == 0
    self.index -= 1 if @index > @item_max - 1
    self.contents = Bitmap.new(width - 32, row_max * 32)
    (0...@item_max).each {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = $game_party.item_number(item.id)
    x = 4
    y = index * 32
    rect = Rect.new(x, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    bitmap = RPG::Cache.icon(item.icon_name)
    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), 255)
    self.contents.draw_text(x + 28, y, 212, 32, item.name)
    self.contents.draw_text(x + 28, y, 244, 32, ': ' + number.to_s, 2)
  end

  def update_help
    KyoShopOrders.goods_id = self.item.id
    @help_window.set_text(self.item.description)
  end
end

class Window_ShopStatus
  alias kyon_discounts_win_shop_status_refresh refresh
  def refresh
    if @investment
      refresh_investment
      return
    end
    kyon_discounts_win_shop_status_refresh
  end

  def investment=(bool)
    @investment = bool
    refresh
  end

  def refresh_investment
    shares = $game_system.shop_shares[$game_variables[KyoShop::STORECODEVARID]]
    contents.font.color = system_color
    contents.draw_text(0, 0, 240, 32, KyoShopLabels::TOTALSHARES)
    contents.font.color = normal_color
    contents.draw_text(0, 0, 240, 32, shares.to_s, 2)
  end
end

class Interpreter
  alias kyon_discounts_inter_comm_302 command_302
  def command_302
    if $game_switches[KyoShop::GOODSSWITCHID]
      KyoShopOrders.store_event_id = @event_id
      $game_switches[KyoShop::GOODSSWITCHID] = false
      $game_system.shop_goods = [@parameters]
      loop do
        @index += 1
        if @list[@index].code == 605
          $game_system.shop_goods << @list[@index].parameters
        else
          return false
        end
      end
    end
    kyon_discounts_inter_comm_302
  end
end

class Scene_Shop
  alias kyon_discounts_scn_shop_up update
  def main
    start
    Graphics.transition
    while @keep_loop
      Graphics.update
      Input.update
      update
    end
    Graphics.freeze
    terminate
  end

  def start
    @keep_loop = true
    @stage = :main
    @shop_id = $game_variables[KyoShop::STORECODEVARID]
    @goods = $game_temp.shop_goods.dup
    @orders = $game_system.shop_goods.dup
    update_goods_orders_after_investment
    make_basic_windows
    @discount_window = Window_ShopDiscountCoupon.new
    @discount_window.disappear
    @discount_window.help_window = @help_window
    unless $game_system.shop_goods.empty?
      @order_window = Window_ShopBuy.new($game_system.shop_goods)
      @order_window.disappear
      @order_window.help_window = @help_window
      @option_window = Window_ShopBuyOptions.new
      @option_window.z += 200
      @option_window.disappear
    end
    if (@need_appraisal = KyoShop::APPRAISALS.keys.include?(@shop_id))
      @appraise_item_window = AppraiseItemWindow.new
      @appraise_item_window.visible = false
      @appraise_info_window = AppraiseInfoWindow.new(@shop_id)
      @appraise_info_window.visible = false
      options = KyoShopLabels::APPRAISALOPTIONS.dup
      @appraise_options = Window_Command.new(160, options)
      @appraise_options.disappear
      @appraise_options.x = 240
      @appraise_options.y = 200
      @result_info_window = AppraiseResultWindow.new
      options = KyoShopLabels::APPRAISALHAGGLEOPTIONS.dup
      @favor_options = Window_Command.new(160, options)
      @favor_options.disappear
      @favor_options.x = 240
      @favor_options.y = 200
    else
      @option_window.disable_item(3)
    end
    @purchase_window = Window_ShopBuy.new($game_temp.shop_goods)
    @purchase_window.disappear
    @purchase_window.help_window = @help_window
    @pack_id = [$game_map.map_id, KyoShopOrders.store_event_id]
    goods = $game_system.placed_orders[@pack_id]
    goods ||= []
    @pickup_window = Window_ShopPickUp.new(goods)
    @pickup_window.disappear
    @pickup_window.help_window = @help_window
    @sell_window = Window_ShopSell.new
    @sell_window.disappear
    @sell_window.help_window = @help_window
    @number_window = Window_ShopNumber.new
    @number_window.disappear
    @status_window = Window_ShopStatus.new
    @status_window.visible = false
  end

  def update_goods_orders_after_investment
    gds = []
    orders = []
    stuff = $game_system.check_shares(@shop_id)
    return if stuff.empty?
    stuff.each {|b| gds += strings_goods_conversion(b[1..-1]) if b[0] == :goods
      orders += string_good_conversion(b[1..-1]) if b[0] == :orders }
    $game_system.shop_goods = (@orders + orders).sort.uniq
    $game_temp.shop_goods = (@goods + gds).sort.uniq
  end

  def strings_goods_conversion(strings)
    data = []
    strings.each {|string| data << retrieve_item(string) }
    data
  end

  def retrieve_item(string)
    case string[0,1]
    when 'i' then [0, string[1..-1].to_i]
    when 'w' then [1, string[1..-1].to_i]
    when 'a' then [2, string[1..-1].to_i]
    end
  end

  def make_basic_windows
    @help_window = Window_Help.new
    @command_window = Window_ShopCommand.new
    @gold_window = Window_Gold.new
    @gold_window.x = 480
    @gold_window.y = 64
    @dummy_window = Window_Base.new(0, 128, 640, 352)
    @question_window = Window_ShopDiscountAlert.new
    @question_window.visible = false
  end

  def terminate
    @help_window.dispose
    @command_window.dispose
    @gold_window.dispose
    @dummy_window.dispose
    @purchase_window.dispose
    @pickup_window.dispose
    @sell_window.dispose
    @number_window.dispose
    @status_window.dispose
    @question_window.dispose
    @discount_window.dispose
    $game_variables[KyoShop::STORECODEVARID] = 0
    if @need_appraisal
      @appraise_item_window.dispose
      @appraise_info_window.dispose
      @appraise_options.dispose
      @result_info_window.dispose
      @favor_options.dispose
    end
    return if $game_system.shop_goods.empty?
    @order_window.dispose
    @option_window.dispose
    $game_system.shop_goods.clear
    KyoShopOrders.commissions.clear
    KyoShopOrders.steps.clear
    KyoShopOrders.store_event_id = nil
    @stage = nil
  end

  def update_discount_message
    cd = $game_party.check_discounts
    text = cd ? KyoShopLabels::SOMEDISCOUNTS : KyoShopLabels::NODISCOUNTS
    @question_window.set_text(text)
  end

  def update
    @help_window.update
    @gold_window.update
    @dummy_window.update
    @sell_window.update
    @status_window.update
    case @stage
    when :main then update_command
    when :option then update_option
    when :purchase then update_purchase
    when :place then update_place_order
    when :pickup then update_pickup_order
    when :discount then update_discount
    when :appraise then update_appraisal
    when :appraise_option then update_appraisal_option
    when :appraise_favor then update_appraisal_favor
    when :sell then update_sell
    when :number then update_number
    end
  end

  def update_command
    @command_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      $scene = Scene_Map.new
      return @keep_loop = nil
    elsif Input.trigger?(Input::C)
      case @command_window.index
      when 0 # buy
        $game_system.se_play($data_system.decision_se)
        @command_window.active = false
        if $game_system.shop_goods.empty?
          @discount = 0
          @dummy_window.visible = false
          @question_window.visible = true
          @status_window.visible = true
          @purchase_window.appear
          @purchase_window.refresh
          update_discount_message
          return @stage = :purchase
        else
          @option_window.appear
          return @stage = :option
        end
      when 1 # sell
        $game_system.se_play($data_system.decision_se)
        @command_window.active = false
        @dummy_window.visible = false
        @sell_window.appear
        @sell_window.refresh
        return
      when 2 # quit
        $game_system.se_play($data_system.decision_se)
        $scene = Scene_Map.new
        @keep_loop = nil
      end
    end
  end

  def update_option
    @option_window.update
    @order_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @option_window.disappear
      @status_window.visible = false
      @command_window.active = true
      @dummy_window.visible = true
      return @stage = :main
    elsif Input.trigger?(Input::C)
      shares = $game_system.shop_shares[@shop_id]
      inv_max, inv_price = KyoShop::SHARESMAXMIN
      pos = @option_window.index
      if pos == 3 and !@need_appraisal
        return $game_system.se_play($data_system.buzzer_se)
      end
      if pos == 4 and inv_max == shares
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      @dummy_window.visible = false
      @option_window.disappear
      @question_window.visible = true
      @status_window.visible = true
      case pos
      when 0 # buy
        @discount = 0
        @purchase_window.discount = 0
        disc = $game_system.check_shares(@shop_id)
        disc.each {|b| @purchase_window.discount += b[1] if b[0] == :discount }
        @status_window.item = @purchase_window.item
        @purchase_window.refresh
        @purchase_window.appear
        update_discount_message
        return @stage = :purchase
      when 1 # place order
        @status_window.item = @order_window.item
        @order_window.appear
        @order_window.refresh
        @question_window.set_text(KyoShopLabels::PLACEORDER)
        return @stage = :place
      when 2 # pick up stuff
        @status_window.item = @pickup_window.item
        @pickup_window.appear
        @pickup_window.refresh
        @question_window.set_text(KyoShopLabels::PICKUPORDER)
        return @stage = :pickup
      when 3 # appraisal
        @appraise_item_window.appear
        @appraise_info_window.visible = true
        @result_info_window.visible = true
        @dummy_window.visible = false
        @command_window.visible = false
        @number_window.visible = false
        @status_window.visible = false
        @help_window.set_text(KyoShopLabels::APPRAISALMENULABEL)
        return @stage = :appraise
      when 4 # investments
        @status_window.investment = @investment = true
        inv_max = [inv_max - shares, $game_party.gold / inv_price].min
        fake_item = RPG::Item.new
        fake_item.name = KyoShopLabels::SHARES
        @price = inv_price
        @number_window.set(fake_item, inv_max, inv_price, nil, 10)
        @number_window.appear
        @question_window.set_text(KyoShopLabels::INVESTMENT)
        @stage = :number
      end
    end
  end

  def update_purchase
    @purchase_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      if $game_system.shop_goods.empty?
        @command_window.active = true
        @stage = :main
      else
        @option_window.appear
        @stage = :option
      end
      @discount = 0
      @purchase_window.discount = 0
      @dummy_window.visible = true
      @purchase_window.disappear
      @question_window.visible = false
      @status_window.visible = false
      @status_window.item = nil
      @help_window.set_text("")
      return
    end
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @purchase_window.item
      return
    end
    if Input.trigger?(KyoShop::DISCOUNTBUTTON)
      unless $game_party.check_discounts
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      @purchase_window.disappear
      @discount_window.refresh
      @discount_window.appear
      @question_window.set_text(KyoShopLabels::SELECTDISCOUNT)
      return @stage = :discount
    elsif Input.trigger?(Input::C)
      discount = @purchase_window.discount
      percent = KyoShop.current_price_max
      @item = @purchase_window.item
      @price = @item.price + @item.price * percent / 100
      @price -= @item.price * discount / 100 if discount > 0
      if @item == nil or @price > $game_party.gold
        return $game_system.se_play($data_system.buzzer_se)
      end
      shop_max = KyoShop.current_item_max
      if (number = check_number) == shop_max
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      max = @price == 0 ? shop_max : $game_party.gold / @price
      max = [max, shop_max - number].min
      @purchase_window.disappear
      @number_window.set(@item, max, @price)
      @number_window.appear
      @last_stage = @stage
      @stage = :number
    end
  end

  def update_place_order
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @option_window.appear
      @dummy_window.visible = true
      @order_window.disappear
      @question_window.visible = false
      @status_window.visible = false
      @status_window.item = nil
      @help_window.set_text("")
      return @stage = :option
    end
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @order_window.item
      return
    end
    if Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      @item = @order_window.item
      @price = @item.price
      percent = KyoShopOrders.commissions[@order_window.index]
      percent += KyoShop.current_price_max
      @price += percent * @item.price / 100 if percent > 0
      if @item == nil or @price > $game_party.gold
        return $game_system.se_play($data_system.buzzer_se)
      end
      number = check_number
      shop_max = KyoShop.current_item_max
      if number == shop_max
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      max = @price == 0 ? shop_max : $game_party.gold / @price
      max = [max, shop_max - number].min
      @order_window.disappear
      @place_order = true
      @number_window.set(@item, max, @price, percent)
      @number_window.appear
      @question_window.set_text(KyoShopLabels::FEESAPPLY)
      @last_stage = @stage
      @stage = :number
    end
  end

  def update_pickup_order
    @pickup_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @dummy_window.visible = true
      @question_window.visible = false
      @status_window.visible = false
      @pickup_window.disappear
      @option_window.appear
      return @stage = :option
    end
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @pickup_window.item
      return
    end
    if Input.trigger?(Input::C)
      current_item = @pickup_window.item
      goods = $game_system.placed_orders[@pack_id]
      unless goods
        return $game_system.se_play($data_system.buzzer_se)
      end
      goods = goods[@pickup_window.index]
      unless current_item and goods[3] <= $game_party.steps
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      number = goods[2]
      case current_item
      when RPG::Item then $game_party.gain_item(current_item.id, number)
      when RPG::Weapon then $game_party.gain_weapon(current_item.id, number)
      when RPG::Armor then $game_party.gain_armor(current_item.id, number)
      end
      $game_system.placed_orders[@pack_id].delete_at(@pickup_window.index)
      @pickup_window.deliver($game_system.placed_orders[@pack_id])
    end
  end

  def update_discount
    @discount_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @discount_window.disappear
      @purchase_window.appear
      return @stage = :purchase
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.decision_se)
      @coupons_allowed = KyoShop::COUPON_IDS.include?(@discount_window.item.id)
      @purchase_window.discount -= @discount
      @discount = @discount_window.item.price
      @discount_window.disappear
      @purchase_window.appear
      discount = @purchase_window.discount += @discount
      @purchase_window.refresh
      text = sprintf(KyoShopLabels::APPLYDISCOUNT, discount)
      @question_window.set_text(text)
      @stage = :purchase
    end
  end

  def update_appraisal
    @appraise_item_window.update
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @appraise_info_window.refresh
      return
    end
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @appraise_item_window.disappear
      @appraise_info_window.visible = false
      @result_info_window.visible = false
      @result_info_window.contents.clear
      @appraise_options.disappear
      @dummy_window.visible = true
      @command_window.visible = true
      @number_window.visible = true
      @status_window.visible = true
      @option_window.appear
      @help_window.set_text("")
      return @stage = :option
    elsif Input.trigger?(Input::C)
      if @appraise_item_window.empty?
        return $game_system.se_play($data_system.buzzer_se)
      end
      $game_system.se_play($data_system.decision_se)
      @appraise_options.appear
      @stage = :appraise_option
    end
  end

  def update_appraisal_option
    @appraise_options.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @appraise_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      data = KyoShop::APPRAISALS[@shop_id]
      price = case @appraise_options.index
      when 0 then data[:test_cost]
      when 1 then data[:cost]
      when 2 then -10
      end
      if price == -10 or $game_party.gold < price
        $game_system.se_play($data_system.buzzer_se)
        @appraise_options.disappear
        return @stage = :appraise
      end
      $game_system.se_play($data_system.decision_se)
      item = @appraise_item_window.item
      $game_party.lose_gold(price)
      if rand(100) < data[:rate]
        goods = data[:goods]
        favors = $game_system.shop_favors[@shop_id]
        goods += data[:extras] if data[:help_limit] <= favors
        key = goods[rand(goods.size)]
      else
        key = data[:default]
      end
      kind, id = retrieve_item(key)
      case item.class
      when RPG::Item then $game_party.lose_item(item.id, 1)
      when RPG::Weapon then $game_party.lose_weapon(item.id, 1)
      when RPG::Armor then $game_party.lose_armor(item.id, 1)
      end
      if data[:target].has_key?(key)
        @appraise_options.disappear
        @favor_options.appear
        @result_info_window.ask_favor(new_item)
        @target_item = new_item
        @target_key = key
        @target_points = data[:target][key]
        @haggle_enabled = data[:haggle]
        @haggle_max = data[:overprice]
        return @stage = :appraise_favor
      end
      case kind
      when 0
        new_item = $data_items[id]
        $game_party.gain_item(id, 1)
      when 1
        new_item = $data_weapons[id]
        $game_party.gain_weapon(id, 1)
      when 2
        new_item = $data_armors[id]
        $game_party.gain_armor(id, 1)
      end
      @result_info_window.refresh(new_item)
      @appraise_item_window.refresh
      @gold_window.refresh
      @appraise_options.disappear
      @stage = :appraise
    end
  end

  def update_appraisal_favor
    @favor_options.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @favor_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      case @favor_options.index
      when 0
        if @overprice
          $game_system.se_play($data_system.shop_se)
          $game_system.shop_favors[@shop_id] += @target_points
          price = @overprice
          @target_points = nil
        else
          $game_system.se_play($data_system.decision_se)
          price = @target_item.price
        end
        $game_party.gain_gold(price)
        @overprice = @target_item = nil
      when 1
        unless @haggle_enabled
          return $game_system.se_play($data_system.buzzer_se)
        end
        $game_system.se_play($data_system.decision_se)
        @haggle_enabled = nil
        @overprice = rand(@haggle_max) + 1
        @overprice = 25 if @overprice < 25
        @overprice += @target_item.price
        @result_info_window.make_offer(@overprice)
        return
      when 2
        $game_system.se_play($data_system.decision_se)
        case @target_item.class
        when RPG::Item then $game_party.gain_item(@target_item.id, 1)
        when RPG::Weapon then $game_party.gain_weapon(@target_item.id, 1)
        when RPG::Armor then $game_party.gain_armor(@target_item.id, 1)
        end
        @target_item = nil
        @favor_options.disappear
      end
      return @stage = :appraise
    end
  end

  def check_number
    return number = case @item
    when RPG::Item then $game_party.item_number(@item.id)
    when RPG::Weapon then $game_party.weapon_number(@item.id)
    when RPG::Armor then $game_party.armor_number(@item.id)
    end
  end

  def update_number
    @number_window.update
    if Input.trigger?(Input::B)
      $game_system.se_play($data_system.cancel_se)
      @number_window.disappear
      @number_window.reset_multiplier
      case @command_window.index
      when 0 # buy or place order
        if @place_order
          @place_order = nil
          @order_window.appear
          @question_window.set_text(KyoShopLabels::PLACEORDER)
        elsif @investment
          @investment = nil
          @status_window.investment = nil
          @option_window.appear
          @question_window.visible = false
          @status_window.visible = false
          @dummy_window.visible = true
        else
          @purchase_window.appear
          discount = @purchase_window.discount
          if discount == 0
            update_discount_message
          else
            text = sprintf(KyoShopLabels::APPLYDISCOUNT, discount) + "%"
            @question_window.set_text(text)
          end
        end
      when 1 # sell
        update_discount_message
        @sell_window.appear
        @status_window.visible = false
      end
      @stage = @last_stage
      return @last_stage = nil
    elsif Input.trigger?(Input::C)
      $game_system.se_play($data_system.shop_se)
      @number_window.disappear
      case @command_window.index
      when 0  # buy
        $game_party.lose_gold(@number_window.number * @price)
        number = @number_window.number
        if @place_order
          update_number_place_order(number)
        elsif @investment
          update_number_investment(number)
        else
          update_number_purchase(number)
        end
        return
      when 1  # sell
        number = @number_window.number
        $game_party.gain_gold(number * (@item.price / 2))
        case @item
        when RPG::Item then   $game_party.lose_item(@item.id, number)
        when RPG::Weapon then $game_party.lose_weapon(@item.id, number)
        when RPG::Armor then  $game_party.lose_armor(@item.id, number)
        end
        @gold_window.refresh
        @sell_window.refresh
        @status_window.refresh
        @sell_window.appear
        @status_window.visible = false
        @stage = @last_stage
        return @last_stage = nil
      end
    end
  end

  def update_number_place_order(number)
    steps = $game_party.steps + KyoShopOrders.steps[@order_window.index]
    order = [nil, @item.id, number, steps]
    order[0] = case @item
    when RPG::Item then 0
    when RPG::Weapon then 1
    when RPG::Armor then 2
    end
    $game_system.placed_orders[@pack_id] ||= []
    $game_system.placed_orders[@pack_id] << order
    @pickup_window.deliver($game_system.placed_orders[@pack_id])
    @gold_window.refresh
    @status_window.refresh
    @place_order = nil
    @order_window.refresh
    @order_window.appear
    @question_window.set_text(KyoShopLabels::PLACEORDER)
    @stage = :place
  end

  def update_number_investment(number)
    @investment = nil
    @status_window.investment = nil
    $game_system.shop_shares[@shop_id] += number
    update_goods_orders_after_investment
    @order_window.deliver($game_system.shop_goods)
    @purchase_window.deliver($game_temp.shop_goods)
    @gold_window.refresh
    @question_window.visible = false
    @status_window.visible = false
    @dummy_window.visible = true
    @number_window.reset_multiplier
    @number_window.disappear
    @option_window.appear
    @stage = :option
  end

  def update_number_purchase(number)
    case @item
    when RPG::Item then $game_party.gain_item(@item.id, number)
    when RPG::Weapon then $game_party.gain_weapon(@item.id, number)
    when RPG::Armor then $game_party.gain_armor(@item.id, number)
    end
    if @coupons_allowed
      @coupons_allowed = nil
      $game_party.lose_item(@discount_window.item.id, 1)
      update_discount_message
      @discount_window.refresh
      @purchase_window.discount = 0
      @discount = 0
    end
    @gold_window.refresh
    @status_window.refresh
    @purchase_window.refresh
    @purchase_window.appear
    @stage = :purchase
  end
end

I don't know why I let wulfo convince me of adding such a weird feature, namely the haggling part... =_=


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-15-2019

Well, don't even think I've forgotten about plain old VX, guys! Shocked

I came back with the VX release of KyoDiscounts this time! It's still a beta release, but it's quite functional already. I just need some feedback to make sure it works just as intended. Laughing

Code:
# * KyoDiscounts VX
#   Scripter : Kyonides-Arkanthos
#   v1.5.0 - 2019-01-15

#   Besides the player can also place orders to get an item that is supposed to
#   be found at another store only. The player will be charged an extra fee, but
#   he or she won't need to go back to another store. The player would only need
#   to keep walking for a while before the goods are available at the store.
#   Now the required steps for each placed order will be automatically increased
#   between 0% and 50%, making it look a bit random but also kind of realistic.

# * Unknown Item or Weapon or Armor Appraisals *

#   Use the Game Variable defined in the STORECODEVARID Constant to store the
#   Shop ID that will include the appraisal service.
#   Use the MYSTERIOUS series of Arrays to include as many IDs of unknown items
#   or weapons or armors that will serve as fillers till they get replaced by
#   the actual goods they represent.
#   Follow the Instructions included in the APPRAISALS Hash to define all
#   conditions that will affect an appraiser's task of identifying the item.

#   Script Calls   #

#   $game_party.discount_cards_expire
#      Makes all Discount Cards expire as part of the game's plot.

#   $game_party.disc_card_expire(Card_ID)
#      Makes an specific Discount Card expire as part of the game's plot.

#   KyoShopOrders << [Percent1, Percent2, etc.]
#      Defines a Commission percent for every Item in the Place Order List.

#   KyoShopOrders.steps = [Steps1, Steps2, etc.]
#   KyoShopOrders.steps += [Steps5, Steps6, etc.]
#      Defines Steps required by every Order in the Place Order List.
#      The 2nd call will be required only if you couldn't include all steps.

#   KyoShop.scarcity_lvl = 0 or higher
#     Define all prices and maximum number of units per shop item.
#     0 means no scarcity, 1 or higher reflects how severe it is.
#     You also have to configure the @scarce_limits hash in order to predefine
#     :price and :max per scarcity level. The maximum scarcity level depends on
#     how many values you entered in both :price and :max arrays.
#     In few words, you define the maximum scarcity level ever possible!

module KyoShop
  # Maximum number of units for each shop item
  NUMBERMAX = 99
  # Button that will open the Discount window while on the shop menu
  DISCOUNTBUTTON = Input::A
  # Add Discount Card Object IDs
  DISCOUNT_IDS = [21, 22, 23]
  # Add Discount Coupon Object IDs
  COUPON_IDS = [24, 25, 26]
  # Maximum Steps before Discount Card expires : ID => Steps
  STEPS = { 21 => 500, 22 => 300, 23 => 150 }
  # Exclusive Stores In Game Variable ID
  STORECODEVARID = 1
  # Exclusive Stores List : Object ID => Exclusive Store Code
  EXCLUSIVESTORES = { 35 => 102 }
  # Switch ID : deactivates Store to add Goods found elsewhere
  GOODSSWITCHID = 1
  # Store IDs for stores where you have invested some gold
  INVESTSTOREIDS = [101]
  # Maximum Number of Shares & Share Price
  SHARESMAXMIN = [10000, 100]
  INVESTMENTS = {} # Store Investments - Do Not Edit This Line
  INVESTMENTS.default = {} # Do Not Edit This Line
  # Available Improvements #
  # :discount : [:discount, 25]
  # :goods    : [:goods, 'i10', 'w4', 'a6']
  # :orders   : [:orders, 'i11', 'w5', 'a7']
  # [Store ID] = { Shares => Prize, Shares => Another Prize, etc. }
  INVESTMENTS[101] = { 50 => [:goods,'i10','w5','a6'], 100 => [:discount,10] }
  APPRAISALS = {} # Do Not Edit This Line!
  # [Store ID] = { appraisal cost => $, estimate cost => $, success rate => %,
  # times you can help the a. => 0, bad result => "i1", goods => [item4, etc.] }
  APPRAISALS[101] = { :cost => 150, :test_cost => 75, :rate => 10,
      :default => 'i1', :help_limit => 5, :haggle => true,
      :target => { 'i9' => 1, 'i10' => 2 },
      :goods => ['i2','i3','i9','i10'], :extras => ['i11'] }
  # Add Item IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSITEMS = []
  # Add Weapon IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSWEAPONS = []
  # Add Armor IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSARMORS = []
  @scarce_limits = {
    :price  => [0, 25, 50, 100, 250, 350, 500, 650, 800],
    :max => [NUMBERMAX, NUMBERMAX - 10, NUMBERMAX - 25, NUMBERMAX - 35,
        NUMBERMAX - 50, NUMBERMAX - 65, NUMBERMAX - 80, NUMBERMAX - 90, 1]
    #:item => [1, 2, 3, 4, 5, 6],
    #:weapon => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
    #:armor => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
  }
  @scarce_lvl = 0 # Initial Level
  def self.current_item_max() @scarce_limits[:max][@scarce_lvl] end
  def self.current_price_max() @scarce_limits[:price][@scarce_lvl] end
  def self.scarcity_limits() @scarce_limits end
  def self.scarcity_lvl() @scarce_lvl end
  def self.scarcity_lvl=(lvl) @scarce_lvl = lvl end
end


module KyoShopLabels
  # Buy Stuff & Place Order & Pick Up Items Label
  BUYPLACEPICKUP = ['Buy Items', 'Place Order', 'Pick Up Items', 'Invest']
  # Item Price Data Labels
  PRICEDATA = ['Basic Price', 'Commission', 'Discount', 'Total Price']
  # Place an Order Label
  PLACEORDER = 'Do you wish to place an order?'
  # Pick Up Order Label
  PICKUPORDER = 'Do you want to pick up an order?'
  # No Order Found Label
  NOORDERFOUND = 'There is nothing left, boss!'
  # Available Discounts Label
  SOMEDISCOUNTS = 'Press A to get a discount'
  # No Discount Available Label
  NODISCOUNTS = 'No Discount Available'
  # Select a Discount Card or Coupon Label
  SELECTDISCOUNT = 'Choose a Card or Coupon'
  # Apply Discount Label
  APPLYDISCOUNT = 'Discount Applied'
  # Commission Fees Apply Label
  FEESAPPLY = 'Special Fees Apply'
  # Discount Card's Steps Left Label
  STEPSLEFT = " %s steps left."
  # Investment Label...
  INVESTMENT = 'Want to invest in this store?'
  # Share Number Label
  SHARES = 'Share Number'
  # Adquired or Purchased Shares Label
  TOTALSHARES = 'Total Shares'
  # Need a Discount Label
  NEEDADISCOUNT = 'Need a Discount?'
  # Pick Item to be Appraised Label
  APPRAISALMENULABEL = "Appraisal Menu"
  # Appraisal Window Labels
  APPRAISALLABELS = ["Quick Test Cost", "Normal Cost"]
  # Appraisal Options Labels
  APPRAISALOPTIONS = ["Quick Test", "Detailed Test", "Cancel"]
  # Purchase Offer and Haggle Labels
  APPRAISALHAGGLEOPTIONS = ["Accept", "Haggle", "Decline"]
  # Appraisal End Result Labels
  APPRAISALRESULTLABELS = [
    "The item at hand is nothing else but... %s",
    "I think it might be worth some... %s",
    "I've been searching for some %s!",
    "Now I want to make a deal.",
    "What if I make a better offer?",
    "Would you accept some %s?"
  ]
end
# DO NOT EDIT ANYTHING ELSE #
module KyoShopOrders
  @goods = []
  @commissions = []
  @steps = []
  class << self
    attr_accessor :store_id, :goods_id, :goods
    attr_reader :steps, :commissions
    def steps=(val) @steps = val.map {|n| n + rand((n / 2) + 2) } end
    def <<(val)
      @commissions += val
      @commissions = @commissions.flatten
    end
  end
end

class Game_System
  attr_reader :placed_orders, :shop_shares, :shop_favors
  alias kyon_discounts_gm_sys_init initialize
  def initialize
    @placed_orders = {}
    @shop_shares = {}
    @shop_favors = {}
    @placed_orders.default = []
    @shop_shares.default = 0
    @shop_favors.default = 0
    kyon_discounts_gm_sys_init
  end

  def disc_store?(disc_id) !KyoShop::EXCLUSIVESTORES[disc_id] end

  def excl_disc_store?(disc_id)
    exclusive = KyoShop::EXCLUSIVESTORES[disc_id]
    exclusive == $game_variables[KyoShop::STORECODEVARID]
  end

  def check_shares(shop_id)
    results = []
    shares = @shop_shares[shop_id]
    investments = KyoShop::INVESTMENTS[shop_id]
    limits = KyoShop::INVESTMENTS[shop_id].keys.sort
    results = investments.select{|limit| shares >= limit[0] }.map {|r| r[1] }
  end
end

class Game_Party
  attr_reader :discounts
  alias kyon_discounts_gm_party_init initialize
  alias kyon_discounts_gm_party_gain_item gain_item
  def initialize
    @discounts = {}
    kyon_discounts_gm_party_init
  end

  def gain_item(item, n, equip=false)
    kyon_discounts_gm_party_gain_item(item, n, equip)
    return if item == nil or n == 0
    return unless KyoShop::DISCOUNT_IDS.include?(item.id)
    item_id = item.id
    if @discounts[item_id]
      @discounts[item_id] += KyoShop::STEPS[item_id]
      @items[item_id] = 1
    else
      @discounts[item_id] = KyoShop::STEPS[item_id]
    end
  end

  def check_discounts
    unless @discounts.empty?
      for did in KyoShop::DISCOUNT_IDS
        next unless @discounts[did] and @discounts[did] > 0
        return true if $game_system.disc_store?(did)
        return true if $game_system.excl_disc_store?(did)
      end
    end
    for cid in KyoShop::COUPON_IDS
      next unless @items[cid] and @items[cid] > 0
      return true if $game_system.disc_store?(cid)
      return true if $game_system.excl_disc_store?(cid)
    end
    return false
  end

  def decrease_discounts
    KyoShop::DISCOUNT_IDS.each {|n| next unless @discounts[n]
      @discounts[n] -= 1 if @discounts[n] > 0 }
  end

  def discount_cards_expire
    KyoShop::DISCOUNT_IDS.each {|n| @discounts[n] = 0 if @discounts[n] }
  end

  def disc_card_expire(dc_id) @discounts[dc_id] = 0 end
  def item_include?(item_id) @items[item_id] and @items[item_id] > 0 end
end

class Game_Player
  alias kyon_discounts_coupons_gm_player_increase_steps increase_steps
  def increase_steps
    kyon_discounts_coupons_gm_player_increase_steps
    $game_party.decrease_discounts
  end
end

class Game_Interpreter
  alias kyon_discounts_game_inter_comm_302 command_302
  def command_302
    if $game_switches[KyoShop::GOODSSWITCHID]
      KyoShopOrders.store_id = @event_id
      $game_switches[KyoShop::GOODSSWITCHID] = false
      KyoShopOrders.goods = [@params[0,2]]
      loop do
        @index += 1
        if @list[@index].code == 605
          KyoShopOrders.goods << @list[@index].parameters
        else
          return false
        end
      end
    end
    kyon_discounts_game_inter_comm_302
  end
end

class Window_Base
  def appear
    self.active = true
    self.visible = true
  end

  def disappear
    self.active = false
    self.visible = false
  end

  def draw_currency_value(value, x, y, width)
    c = self.contents
    cx = c.text_size(Vocab::gold).width
    c.font.color = normal_color
    c.draw_text(x - 8, y, width-cx-2, WLH, value, 2)
    c.font.color = system_color
    c.draw_text(x, y, width, WLH, Vocab::gold, 2)
  end
end

class Window_KyoShopHelp < Window_Help
  def set_text(text, align=0)
    if KyoShop::DISCOUNT_IDS.include?(KyoShopOrders.goods_id)
      steps = $game_party.discounts[KyoShopOrders.goods_id].to_s
      text = sprintf(KyoShopLabels::STEPSLEFT, steps)
      KyoShopOrders.goods_id = nil
    end
    super(text, align)
  end
end

class Window_Item
  alias kyon_discounts_win_item_up_help update_help
  def update_help
    KyoShopOrders.goods_id = self.item.id
    kyon_discounts_win_item_up_help
  end
end

class AppraiseItemWindow < Window_Selectable
  def initialize
    super(0, 56, 544-160, 280)
    @column_max = 1
    refresh
    self.index = 0
  end

  def refresh
    self.contents.clear
    @data = []
    for n in KyoShop::MYSTERIOUSITEMS
      next if $game_party.item_number(n) == 0
      @data << $data_items[n]
    end
    for i in KyoShop::MYSTERIOUSWEAPONS
      next if $game_party.weapon_number(i) == 0
      @data << $data_weapons[i]
    end
    for i in KyoShop::MYSTERIOUSARMORS
      next if $game_party.armor_number(i) == 0
      @data << $data_armors[i]
    end
    @item_max = @data.size
    return if @item_max == 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    @item_max.times{|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    c = self.contents
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    c.fill_rect(rect, Color.new(0, 0, 0, 0))
    bit = RPG::Cache.icon(item.icon_name)
    c.blt(x, y + 4, bit, Rect.new(0, 0, 24, 24), 255)
    c.draw_text(x + 28, y, 212, 32, item.name, 0)
    c.draw_text(x + 240, y, 16, 32, ":", 1)
    c.draw_text(x + 256, y, 24, 32, number.to_s, 2)
  end
  def item() @data[@index] end
  def empty?() @data.empty? end
end

class AppraiseInfoWindow < Window_Base
  def initialize(store_id)
    super(384, 112, 160, 224)
    @data = KyoShop::APPRAISALS[store_id]
    @labels = KyoShopLabels::APPRAISALLABELS.dup
    @currency = Vocab.gold
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end

  def refresh
    aw = width - 32
    contents.clear
    contents.font.color = system_color
    contents.draw_text(0, 0, aw, 24, @labels[0])
    contents.draw_text(0, 48, aw, 24, @labels[1])
    contents.draw_text(0, 24, aw, 24, @currency, 2)
    contents.draw_text(0, 72, aw, 24, @currency, 2)
    contents.font.color = normal_color
    contents.draw_text(0, 24, width - 48, 24, @data[:test_cost].to_s, 2)
    contents.draw_text(0, 72, width - 48, 24, @data[:cost].to_s, 2)
  end
end

class AppraiseResultWindow < Window_Base
  def initialize
    super(0, 334, 544, 84)
    @labels = KyoShopLabels::APPRAISALRESULTLABELS.dup
    @currency = Vocab.gold #draw_currency_value(value, x, y, width)
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def refresh(item)
    contents.clear
    result = sprintf(@labels[0], item.name)
    cost = sprintf(@labels[1], item.price) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, cost)
  end

  def ask_favor(item)
    contents.clear
    result = sprintf(@labels[2], item.name)
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, @labels[3])
  end

  def make_offer(overprice)
    contents.clear
    result = sprintf(@labels[5], overprice) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, @labels[4])
    contents.draw_text(0, 24, width - 32, 24, result)
  end
end

class Window_ShopBuyPlace < Window_Selectable
  attr_accessor :discount
  attr_reader :discounts
  def initialize(shop_goods, discounts=[])
    super(0, 112, 304, 248)
    @shop_goods = shop_goods
    @discount = 0
    @discounts = discounts
    refresh
    self.index = 0
  end

  def deliver(goods)
    @shop_goods = goods
    if goods.size - 1 < @index
      @index = goods.size > 0 ? (@index + goods.size - 1) % goods.size : 0
      update_cursor_rect
    end
    refresh
    self.index = 0
  end

  def item() @data[self.index] end

  def refresh
    @data = []
    for goods_item in @shop_goods
      item = case goods_item[0]
      when 0 then $data_items[goods_item[1]]
      when 1 then $data_weapons[goods_item[1]]
      when 2 then $data_armors[goods_item[1]]
      end
      @data << item if item
    end
    @item_max = @data.size
    create_contents
    @item_max.times {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = $game_party.item_number(item)
    enabled = (item.price <= $game_party.gold and number < 99)
    rect = item_rect(index)
    self.contents.clear_rect(rect)
    draw_item_name(item, rect.x, rect.y, enabled)
    rect.width -= 4
    fee = @discounts.empty? ? @discount : @discounts[index]
    fee = item.price * fee / 100
    self.contents.draw_text(rect, item.price + fee, 2)
  end

  def update_help
    @help_window.set_text(item == nil ? "" : item.description)
  end
end

class Window_ShopNumber
  def initialize(x, y)
    super(x, y, 304, 248)
    @item = nil
    @max = 1
    @price = 0
    @number = 1
    @percent = 0
    @multiplier = 1
  end

  def reset_multiplier
    @multiplier = 1
    @number = 1
    refresh
  end

  def set(item, max, price, percent=0, multiplier=1)
    @item = item
    @max = max
    @price = price
    @number = 1
    @multiplier = multiplier
    @percent = percent
    refresh
  end

  def refresh
    self.contents.clear
    draw_item_name(@item, 0, 96)
    self.contents.font.color = normal_color
    if @multiplier == 1
      cx1, cx2, cx3, cw1, cw2 = [212, 240, 244, 28, 28]
    else
      cx1, cx2, cx3, cw1, cw2 = [196, 202, 212, 68, 64]
    end
    self.contents.draw_text(cx1, 96, 20, WLH, "")
    self.contents.draw_text(cx2, 96, cw1, WLH, @number, 2)
    self.cursor_rect.set(cx3, 96, cw2, WLH)
    if @percent == 0 or @multiplier > 1
      draw_currency_value(@price * @number, 4, 96 + WLH * 2, 264)
      return
    end
    draw_currency_value(@item.price * @number, 4, 72 + WLH * 2, 264)
    draw_percent_value(@percent, 4, 96 + WLH * 2, 264)
    end_price = @item.price + @item.price * @percent / 100
    draw_currency_value(end_price * @number, 4, 120 + WLH * 2, 264)
    draw_price_labels(x - 20, 120, 160)
  end

  def draw_percent_value(value, x, y, width)
    cx = contents.text_size(Vocab::gold).width
    self.contents.font.color = normal_color
    self.contents.draw_text(x - 8, y, width-cx-2, WLH, value, 2)
    text = KyoShopLabels::PRICEDATA[@percent < 0 ? 2 : 1]
    self.contents.draw_text(x + 40, y, width, WLH, text)
    self.contents.font.color = system_color
    self.contents.draw_text(x, y, width, WLH, '%', 2)
  end

  def draw_price_labels(x, y, w)
    self.contents.font.color = normal_color
    self.contents.draw_text(x, y, w, WLH, KyoShopLabels::PRICEDATA[0], 2)
    self.contents.draw_text(x, y + 48, w, WLH, KyoShopLabels::PRICEDATA[3], 2)
  end
end

class Window_ShopPickUp < Window_ShopBuyPlace
  def draw_item(index)
    item = @data[index]
    qty, steps = @shop_goods[index][2..3]
    number = $game_party.item_number(item)
    enough = (number + qty < 100 and steps <= $game_party.steps)
    self.contents.font.color.alpha = enough ? 255 : 128
    y = index * 24
    draw_icon(item.icon_index, 0, y, enough)
    self.contents.draw_text(32, y - 4, 212, 32, item.name, 0)
    self.contents.draw_text(180, y - 4, 88, 32, qty.to_s, 2)
  end
end

class Window_ShopDiscountAlert < Window_Base
  def initialize
    super(0, 360, 304, 56)
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def set_text(text)
    self.contents.clear
    self.contents.draw_text(0, 0, 272, 24, text)
  end
end

class Window_ShopDiscountCoupon < Window_Selectable
  def initialize
    super(0, 112, 304, 248)
    self.index = 0
    refresh
  end

  def item() @data[self.index] end

  def refresh
    @data = []
    gs = $game_system
    dc_ids = $game_party.discounts.keys.sort
    dc_ids.each {|i| next if $game_party.discounts[i] == 0
      next unless gs.disc_store?(i) or gs.excl_disc_store?(i)
      @data << $data_items[i] }
    KyoShop::COUPON_IDS.each {|i| next unless $game_party.item_include?(i)
      @data << $data_items[i] }
    @item_max = @data.size
    self.index -= 1 if @index > @item_max - 1
    create_contents
    @item_max.times {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = $game_party.item_number(item)
    y = index * 24
    rect = Rect.new(4, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    enabled = $game_party.item_can_use?(item)
    draw_item_name(item, rect.x, rect.y, enabled)
    self.contents.draw_text(32, y, 236, 24, ': ' + number.to_s, 2)
  end

  def update_help
    KyoShopOrders.goods_id = self.item.id
    @help_window.set_text(self.item.description)
  end
end

class Window_ShopStatus
  alias kyon_discounts_win_shop_status_refresh refresh
  def investment=(bool)
    @investment = bool
    refresh
  end

  def refresh
    if @investment
      refresh_investment
      return
    end
    kyon_discounts_win_shop_status_refresh
  end

  def refresh_investment
    self.contents.clear
    shares = $game_system.shop_shares[$game_variables[KyoShop::STORECODEVARID]]
    contents.font.color = system_color
    contents.draw_text(0, 0, 200, 32, KyoShopLabels::TOTALSHARES)
    contents.font.color = normal_color
    contents.draw_text(0, 0, 208, 32, shares.to_s, 2)
  end
end

class Scene_Shop
  def start
    @stage = :main
    @shop_id = $game_variables[KyoShop::STORECODEVARID]
    @goods = $game_temp.shop_goods.dup
    @orders = KyoShopOrders.goods.dup
    update_goods_orders_after_investment
    create_menu_background
    create_command_window
    make_basic_data_windows
    make_shop_windows
    make_discount_order_pickup_windows
    make_appraisal_windows
  end

  def make_basic_data_windows
    @help_window = Window_Help.new
    @gold_window = Window_Gold.new(384, 56)
    @dummy_window = Window_Base.new(0, 112, 544, 304)
    @status_window = Window_ShopStatus.new(304, 112)
    @status_window.visible = false
  end

  def make_shop_windows
    @buy_window = Window_ShopBuyPlace.new($game_temp.shop_goods)
    @buy_window.disappear
    @buy_window.help_window = @help_window
    @sell_window = Window_ShopSell.new(0, 112, 544, 304)
    @sell_window.disappear
    @sell_window.help_window = @help_window
    @number_window = Window_ShopNumber.new(0, 112)
    @number_window.disappear
  end

  def make_discount_order_pickup_windows
    @question_window = Window_ShopDiscountAlert.new
    @question_window.visible = false
    @discount_window = Window_ShopDiscountCoupon.new
    @discount_window.disappear
    @discount_window.help_window = @help_window
    commands = KyoShopLabels::BUYPLACEPICKUP.dup
    commands.pop unless KyoShop::INVESTSTOREIDS.include?(@shop_id)
    @extras_window = Window_Command.new(200, commands)
    @extras_window.x = (544 - 200) / 2
    @extras_window.y = 112
    @extras_window.disappear
    unless KyoShopOrders.goods.empty?
      goods = KyoShopOrders.goods
      @order_window = Window_ShopBuyPlace.new(goods, KyoShopOrders.commissions)
      @order_window.disappear
      @order_window.help_window = @help_window
    end
    @pack_id = [$game_map.map_id, KyoShopOrders.store_id]
    goods = $game_system.placed_orders[@pack_id]
    unless goods
      goods = []
      @no_orders = true
      @extras_window.draw_item(2, nil)
    end
    @pickup_window = Window_ShopPickUp.new(goods)
    @pickup_window.disappear
    @pickup_window.help_window = @help_window
  end

  def make_appraisal_windows
    if (@need_appraisal = KyoShop::APPRAISALS.keys.include?(@shop_id))
      @appraise_item_window = AppraiseItemWindow.new
      @appraise_item_window.visible = false
      @appraise_info_window = AppraiseInfoWindow.new(@shop_id)
      @appraise_info_window.visible = false
      options = KyoShopLabels::APPRAISALOPTIONS.dup
      @appraise_options = Window_Command.new(160, options)
      @appraise_options.disappear
      @appraise_options.x = 240
      @appraise_options.y = 200
      @result_info_window = AppraiseResultWindow.new
      @result_info_window.visible = false
      options = KyoShopLabels::APPRAISALHAGGLEOPTIONS.dup
      @favor_options = Window_Command.new(160, options)
      @favor_options.disappear
      @favor_options.x = 240
      @favor_options.y = 200
    else
      @extras_window.draw_item(3, nil)
    end
  end

  def update_goods_orders_after_investment
    gds = []
    orders = []
    stuff = $game_system.check_shares(@shop_id)
    return if stuff.empty?
    stuff.each {|b| gds += strings_goods_conversion(b[1..-1]) if b[0] == :goods
      orders += string_good_conversion(b[1..-1]) if b[0] == :orders }
    KyoShopOrders.goods = (@orders + orders).sort.uniq
    $game_temp.shop_goods = (@goods + gds).sort.uniq
  end

  def strings_goods_conversion(strings)
    data = []
    strings.each {|string| data << retrieve_item(string) }
    data
  end

  def retrieve_item(string)
    case string[0,1]
    when 'i' then [0, string[1..-1].to_i]
    when 'w' then [1, string[1..-1].to_i]
    when 'a' then [2, string[1..-1].to_i]
    end
  end

  def update_discount_message
    if @buy_window.discount < 0
      text = sprintf(KyoShopLabels::APPLYDISCOUNT, @discount_window.item.price)
    else
      cd = $game_party.check_discounts
      text = cd ? KyoShopLabels::SOMEDISCOUNTS : KyoShopLabels::NODISCOUNTS
    end
    @question_window.set_text(text)
  end

  def terminate
    dispose_menu_background
    dispose_command_window
    @discount_window.dispose
    @extras_window.dispose
    @order_window.dispose
    @pickup_window.dispose
    @question_window.dispose
    @help_window.dispose
    @gold_window.dispose
    @dummy_window.dispose
    @buy_window.dispose
    @sell_window.dispose
    @number_window.dispose
    @status_window.dispose
    if @need_appraisal
      @appraise_item_window.dispose
      @appraise_info_window.dispose
      @appraise_options.dispose
      @result_info_window.dispose
      @favor_options.dispose
    end
    KyoShopOrders.goods.clear
    KyoShopOrders.steps.clear
    KyoShopOrders.commissions.clear
    KyoShopOrders.store_id = 0
    @stage = @shop_id = nil
  end

  def update
    super
    update_menu_background
    @help_window.update
    @gold_window.update
    @number_window.update
    @status_window.update
    case @stage
    when :main then update_command
    when :option then update_extras
    when :purchase then update_purchase
    when :place then update_place_order
    when :pickup then update_pickup_order
    when :discount then update_discount
    when :appraise then update_appraisal
    when :appraise_option then update_appraisal_option
    when :appraise_favor then update_appraisal_favor
    when :sell then update_sell
    when :number then update_number
    end
  end

  def update_command
    @command_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      $scene = Scene_Map.new
      return
    elsif Input.trigger?(Input::C)
      case @command_window.index
      when 0  # buy
        Sound.play_decision
        @command_window.active = false
        @extras_window.appear
        @question_window.visible = true
        update_discount_message
        return @stage = :option
      when 1  # sell
        return Sound.play_buzzer if $game_temp.shop_purchase_only
        Sound.play_decision
        @command_window.active = false
        @dummy_window.visible = false
        @sell_window.appear
        @sell_window.refresh
        return @stage = :sell
      when 2  # Quit
        Sound.play_decision
        $scene = Scene_Map.new
      end
    end
  end

  def update_extras
    @extras_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @extras_window.disappear
      @question_window.visible = false
      @command_window.active = true
      return @stage = :main
    elsif Input.trigger?(Input::C)
      if @no_orders and @extras_window.index == 2
        return Sound.play_buzzer
      end
      shares = $game_system.shop_shares[@shop_id]
      inv_max, inv_price = KyoShop::SHARESMAXMIN
      if @extras_window.index == 3 and inv_max == shares
        return Sound.play_buzzer
      end
      Sound.play_decision
      @extras_window.disappear
      @dummy_window.visible = false
      @status_window.visible = true
      @question_window.visible = @extras_window.index != 3
      update_discount_message
      case @extras_window.index
      when 0 # purchase
        @status_window.item = @buy_window.item
        @buy_window.appear
        @buy_window.refresh
        @last_stage = :option
        return @stage = :purchase
      when 1 # place order
        @status_window.item = @order_window.item
        @order_window.appear
        @question_window.set_text(KyoShopLabels::FEESAPPLY)
        return @stage = :place
      when 2 # pick up order
        @status_window.item = @pickup_window.item
        @pickup_window.appear
        return @stage = :pickup
      when 3 # appraisals
        @appraise_item_window.appear
        @appraise_info_window.visible = true
        @result_info_window.visible = true
        @dummy_window.visible = false
        @command_window.visible = false
        @number_window.visible = false
        @status_window.visible = false
        @help_window.set_text(KyoShopLabels::APPRAISALMENULABEL)
        return @stage = :appraise
      when 4 # investments
        @status_window.investment = @investment = true
        inv_max = [inv_max - shares, $game_party.gold / inv_price].min
        fake_item = RPG::Item.new
        fake_item.name = KyoShopLabels::SHARES
        @price = inv_price
        @number_window.set(fake_item, inv_max, inv_price, 0, 10)
        @number_window.appear
        @question_window.set_text(KyoShopLabels::INVESTMENT)
        @stage = :number
      end
    end
  end

  def update_purchase
    @buy_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @buy_window.disappear
      @status_window.visible = false
      @question_window.visible = false
      @dummy_window.visible = true
      @extras_window.appear
      @status_window.item = nil
      @help_window.set_text("")
      return @stage = :option
    elsif Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @buy_window.item
      return
    elsif Input.trigger?(KyoShop::DISCOUNTBUTTON)
      unless $game_party.check_discounts
        return Sound.play_buzzer
      end
      Sound.play_decision
      @buy_window.disappear
      @discount_window.refresh
      @discount_window.appear
      @question_window.set_text(KyoShopLabels::SELECTDISCOUNT)
      return @stage = :discount
    elsif Input.trigger?(Input::C)
      @item = @buy_window.item
      number = $game_party.item_number(@item)
      shop_max = KyoShop.current_item_max
      if @item == nil or @item.price > $game_party.gold or number == shop_max
        return Sound.play_buzzer
      end
      Sound.play_decision
      max = @item.price == 0 ? shop_max : $game_party.gold / @item.price
      max = [max, shop_max - number].min
      @buy_window.disappear
      discount = @buy_window.discount < 0 ? @buy_window.discount : 0
      @number_window.set(@item, max, @item.price, discount)
      @number_window.appear
      @last_stage = :purchase
      @stage = :number
    end
  end

  def update_place_order
    @order_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @status_window.disappear
      @order_window.disappear
      @extras_window.appear
      @dummy_window.visible = true
      @question_window.visible = false
      return @stage = :option
    elsif Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @order_window.item
      return
    elsif Input.trigger?(Input::C)
      @item = @order_window.item
      @price = @item.price
      percent = KyoShopOrders.commissions[@order_window.index]
      @price += percent * @item.price / 100 if percent > 0
      number = $game_party.item_number(@item)
      shop_max = KyoShop.current_item_max
      if @item == nil or @price > $game_party.gold or number == shop_max
        Sound.play_buzzer
        return
      end
      Sound.play_decision
      max = @price == 0 ? shop_max : $game_party.gold / @price
      max = [max, shop_max - number].min
      @order_window.disappear
      @number_window.set(@item, max, @price, percent)
      @number_window.appear
      @last_stage = :place
      @stage = :number
    end
  end

  def update_pickup_order
    @pickup_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @status_window.disappear
      @pickup_window.disappear
      @extras_window.appear
      @dummy_window.visible = true
      @question_window.visible = false
      return @stage = :option
    elsif Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @pickup_window.item
      return
    elsif Input.trigger?(Input::C)
      unless (goods = $game_system.placed_orders[@pack_id])
        return Sound.play_buzzer
      end
      current_item = @pickup_window.item
      goods = goods[@pickup_window.index]
      unless current_item and goods[3] <= $game_party.steps
        return Sound.play_buzzer
      end
      Sound.play_decision
      number = goods[2]
      $game_party.gain_item(current_item, number)
      $game_system.placed_orders[@pack_id].delete_at(@pickup_window.index)
      @pickup_window.reload_goods($game_system.placed_orders[@pack_id])
      @last_stage = :pickup
      @stage = :number
    end
  end

  def update_discount
    @discount_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @discount_window.disappear
      @buy_window.appear
      return @stage = :purchase
    elsif Input.trigger?(Input::C)
      Sound.play_decision
      @coupons_allowed = KyoShop::COUPON_IDS.include?(@discount_window.item.id)
      @buy_window.discount = -@discount_window.item.price
      @buy_window.refresh
      @discount_window.disappear
      @buy_window.appear
      update_discount_message
      @stage = :purchase
    end
  end

  def update_appraisal
    @appraise_item_window.update
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @appraise_info_window.refresh
      return
    end
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @appraise_item_window.disappear
      @appraise_info_window.visible = false
      @question_window.visible = false
      @result_info_window.visible = false
      @result_info_window.contents.clear
      @appraise_options.disappear
      @dummy_window.visible = true
      @command_window.visible = true
      @extras_window.appear
      @help_window.set_text("")
      return @stage = :option
    elsif Input.trigger?(Input::C)
      return Sound.play_buzzer if @appraise_item_window.empty?
      Sound.play_decision
      @appraise_options.appear
      @stage = :appraise_option
    end
  end

  def update_appraisal_option
    @appraise_options.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @appraise_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      data = KyoShop::APPRAISALS[@shop_id]
      price = case @appraise_options.index
      when 0 then data[:test_cost]
      when 1 then data[:cost]
      when 2 then -10
      end
      if price == -10 or $game_party.gold < price
        Sound.play_buzzer
        @appraise_options.disappear
        return @stage = :appraise
      end
      Sound.play_decision
      item = @appraise_item_window.item
      $game_party.lose_gold(price)
      if rand(100) < data[:rate]
        goods = data[:goods]
        favors = $game_system.shop_favors[@shop_id]
        goods += data[:extras] if data[:help_limit] <= favors
        key = goods[rand(goods.size)]
      else
        key = data[:default]
      end
      kind, id = retrieve_item(key)
      case item.class
      when RPG::Item then $game_party.lose_item(item.id, 1)
      when RPG::Weapon then $game_party.lose_weapon(item.id, 1)
      when RPG::Armor then $game_party.lose_armor(item.id, 1)
      end
      if data[:target].has_key?(key)
        @appraise_options.disappear
        @favor_options.appear
        @result_info_window.ask_favor(new_item)
        @target_item = new_item
        @target_key = key
        @target_points = data[:target][key]
        @haggle_enabled = data[:haggle]
        @haggle_max = data[:overprice]
        return @stage = :appraise_favor
      end
      case kind
      when 0
        new_item = $data_items[id]
        $game_party.gain_item(id, 1)
      when 1
        new_item = $data_weapons[id]
        $game_party.gain_weapon(id, 1)
      when 2
        new_item = $data_armors[id]
        $game_party.gain_armor(id, 1)
      end
      @result_info_window.refresh(new_item)
      @appraise_item_window.refresh
      @gold_window.refresh
      @appraise_options.disappear
      @stage = :appraise
    end
  end

  def update_appraisal_favor
    @favor_options.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @favor_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      case @favor_options.index
      when 0
        if @overprice
          Sound.play_shop
          $game_system.shop_favors[@shop_id] += @target_points
          price = @overprice
          @target_points = nil
        else
          Sound.play_decision
          price = @target_item.price
        end
        $game_party.gain_gold(price)
        @overprice = @target_item = nil
      when 1
        return Sound.se_play($data_system.buzzer_se) unless @haggle_enabled
        Sound.play_decision
        @haggle_enabled = nil
        @overprice = rand(@haggle_max) + 1
        @overprice = 25 if @overprice < 25
        @overprice += @target_item.price
        @result_info_window.make_offer(@overprice)
        return
      when 2
        Sound.play_decision
        case @target_item.class
        when RPG::Item then $game_party.gain_item(@target_item.id, 1)
        when RPG::Weapon then $game_party.gain_weapon(@target_item.id, 1)
        when RPG::Armor then $game_party.gain_armor(@target_item.id, 1)
        end
        @target_item = nil
        @favor_options.disappear
      end
      return @stage = :appraise
    end
  end

  def update_sell
    @sell_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @command_window.active = true
      @dummy_window.visible = true
      @sell_window.disappear
      @status_window.item = nil
      @help_window.set_text("")
      return @stage = :main
    elsif Input.trigger?(Input::C)
      @item = @sell_window.item
      @status_window.item = @item
      if @item == nil or @item.price == 0
        return Sound.play_buzzer
      end
      Sound.play_decision
      max = $game_party.item_number(@item)
      @sell_window.disappear
      @number_window.set(@item, max, @item.price / 2)
      @number_window.appear
      @status_window.visible = true
      @stage = :number
    end
  end

  def update_number
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @number_window.disappear
      if @extras_window.index == 1
        @order_window.appear
        return @stage = :place
      elsif @extras_window.index == 4
        return update_cancel_investment
      end
      case @command_window.index
      when 0
        @buy_window.appear
        return @stage = :purchase
      when 1  # Sell
        @sell_window.appear
        @status_window.visible = false
        return @stage = :sell
      end
    elsif Input.trigger?(Input::C)
      decide_number_input
    end
  end

  def decide_number_input
    Sound.play_shop
    @number_window.disappear
    case @extras_window.index
    when 1
      decide_number_order
      return
    when 4
      decide_number_investment
      return
    end
    case @command_window.index
    when 0  # Buy
      percent = KyoShop.current_price_max
      price = @item.price + @item.price * percent / 100
      price += price * @buy_window.discount / 100
      $game_party.lose_gold(@number_window.number * price)
      $game_party.gain_item(@item, @number_window.number)
      if @coupons_allowed
        @coupons_allowed = nil
        $game_party.lose_item(@discount_window.item, 1)
        @buy_window.discount = 0
        update_discount_message
        @discount_window.refresh
      end
      @gold_window.refresh
      @buy_window.refresh
      @status_window.refresh
      @buy_window.appear
      return @stage = :purchase
    when 1  # sell
      $game_party.gain_gold(@number_window.number * (@item.price / 2))
      $game_party.lose_item(@item, @number_window.number)
      @gold_window.refresh
      @sell_window.refresh
      @status_window.refresh
      @sell_window.appear
      @status_window.visible = false
      @stage = :sell
    end
  end

  def decide_number_order
    percent = KyoShopOrders.commissions[@order_window.index]
    percent += KyoShop.current_price_max
    price = @item.price + @item.price * percent / 100
    $game_party.lose_gold(@number_window.number * price)
    steps = $game_party.steps + KyoShopOrders.steps[@order_window.index]
    order = [nil, @item.id, @number_window.number, steps]
    order[0] = case @item
    when RPG::Item then 0
    when RPG::Weapon then 1
    when RPG::Armor then 2
    end
    unless $game_system.placed_orders[@pack_id]
      @no_orders = nil
      @extras_window.draw_item(2, true)
    end
    $game_system.placed_orders[@pack_id] << order
    @pickup_window.reload_goods($game_system.placed_orders[@pack_id])
    @status_window.refresh
    @gold_window.refresh
    @order_window.refresh
    @order_window.appear
    @stage = :place
  end

  def decide_number_investment
    $game_system.shop_shares[@shop_id] += @number_window.number
    update_goods_orders_after_investment
    @order_window.deliver(KyoShopOrders.goods)
    @buy_window.deliver($game_temp.shop_goods)
    @gold_window.refresh
    update_cancel_investment
  end

  def update_cancel_investment
    @investment = nil
    @status_window.investment = nil
    @status_window.visible = false
    @question_window.visible = false
    @dummy_window.visible = true
    @number_window.reset_multiplier
    @number_window.disappear
    @extras_window.appear
    @stage = :option
  end
end



RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-17-2019

Here is an updated version of KyoDiscounts VX! I have the need to fix some issues regarding gaining items, weapons and armors, plus simplify a few things here and there... Confused

Code:
# * KyoDiscounts VX
#   Scripter : Kyonides-Arkanthos
#   v1.5.0 - 2019-01-17

#   Besides the player can also place orders to get an item that is supposed to
#   be found at another store only. The player will be charged an extra fee, but
#   he or she won't need to go back to another store. The player would only need
#   to keep walking for a while before the goods are available at the store.
#   Now the required steps for each placed order will be automatically increased
#   between 0% and 50%, making it look a bit random but also kind of realistic.

# * Unknown Item or Weapon or Armor Appraisals *

#   Use the Game Variable defined in the STORECODEVARID Constant to store the
#   Shop ID that will include the appraisal service.
#   Use the MYSTERIOUS series of Arrays to include as many IDs of unknown items
#   or weapons or armors that will serve as fillers till they get replaced by
#   the actual goods they represent.
#   Follow the Instructions included in the APPRAISALS Hash to define all
#   conditions that will affect an appraiser's task of identifying the item.

#   Script Calls   #

#   $game_party.discount_cards_expire
#      Makes all Discount Cards expire as part of the game's plot.

#   $game_party.disc_card_expire(Card_ID)
#      Makes an specific Discount Card expire as part of the game's plot.

#   KyoShopOrders << [Percent1, Percent2, etc.]
#      Defines a Commission percent for every Item in the Place Order List.

#   KyoShopOrders.steps = [Steps1, Steps2, etc.]
#   KyoShopOrders.steps += [Steps5, Steps6, etc.]
#      Defines Steps required by every Order in the Place Order List.
#      The 2nd call will be required only if you couldn't include all steps.

#   KyoShop.scarcity_lvl = 0 or higher
#     Define all prices and maximum number of units per shop item.
#     0 means no scarcity, 1 or higher reflects how severe it is.
#     You also have to configure the @scarce_limits hash in order to predefine
#     :price and :max per scarcity level. The maximum scarcity level depends on
#     how many values you entered in both :price and :max arrays.
#     In few words, you define the maximum scarcity level ever possible!

module KyoShop
  # Maximum number of units for each shop item
  NUMBERMAX = 99
  # Button that will open the Discount window while on the shop menu
  DISCOUNTBUTTON = Input::A
  # Add Discount Card Object IDs
  DISCOUNT_IDS = [21, 22, 23]
  # Add Discount Coupon Object IDs
  COUPON_IDS = [24, 25, 26]
  # Maximum Steps before Discount Card expires : ID => Steps
  STEPS = { 21 => 500, 22 => 300, 23 => 150 }
  # Exclusive Stores In Game Variable ID
  STORECODEVARID = 1
  # Exclusive Stores List : Object ID => Exclusive Store Code
  EXCLUSIVESTORES = { 35 => 102 }
  # Switch ID : deactivates Store to add Goods found elsewhere
  GOODSSWITCHID = 1
  # Store IDs for stores where you have invested some gold
  INVESTSTOREIDS = [101]
  # Maximum Number of Shares & Share Price
  SHARESMAXMIN = [10000, 100]
  INVESTMENTS = {} # Store Investments - Do Not Edit This Line
  INVESTMENTS.default = {} # Do Not Edit This Line
  # Available Improvements #
  # :discount : [:discount, 25]
  # :goods    : [:goods, 'i10', 'w4', 'a6']
  # :orders   : [:orders, 'i11', 'w5', 'a7']
  # [Store ID] = { Shares => Prize, Shares => Another Prize, etc. }
  INVESTMENTS[101] = { 50 => [:goods,'i10','w5','a6'], 100 => [:discount,10] }
  APPRAISALS = {} # Do Not Edit This Line!
  # [Store ID] = { appraisal cost => $, estimate cost => $, success rate => %,
  # times you can help the a. => 0, bad result => "i1", goods => [item4, etc.] }
  APPRAISALS[101] = { :cost => 150, :test_cost => 75, :rate => 10,
      :default => 'i1', :help_limit => 5, :haggle => true,
      :target => { 'i9' => 1, 'i10' => 2 },
      :goods => ['i2','i3','i9','i10'], :extras => ['i11'] }
  # Add Item IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSITEMS = []
  # Add Weapon IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSWEAPONS = []
  # Add Armor IDs for unknown shop goods that need to be appraised by experts
  MYSTERIOUSARMORS = []
  @scarce_limits = {
    :price  => [0, 25, 50, 100, 250, 350, 500, 650, 800],
    :max => [NUMBERMAX, NUMBERMAX - 10, NUMBERMAX - 25, NUMBERMAX - 35,
        NUMBERMAX - 50, NUMBERMAX - 65, NUMBERMAX - 80, NUMBERMAX - 90, 1]
    #:item => [1, 2, 3, 4, 5, 6],
    #:weapon => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
    #:armor => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
  }
  @scarce_lvl = 0 # Initial Level
  def self.current_item_max() @scarce_limits[:max][@scarce_lvl] end
  def self.current_price_max() @scarce_limits[:price][@scarce_lvl] end
  def self.scarcity_limits() @scarce_limits end
  def self.scarcity_lvl() @scarce_lvl end
  def self.scarcity_lvl=(lvl) @scarce_lvl = lvl end
end


module KyoShopLabels
  # Buy Stuff & Place Order & Pick Up Items Label
  BUYPLACEPICKUP = ['Buy Items', 'Place Order', 'Pick Up Items', 'Invest']
  # Item Price Data Labels
  PRICEDATA = ['Basic Price', 'Commission', 'Discount', 'Total Price']
  # Place an Order Label
  PLACEORDER = 'Do you wish to place an order?'
  # Pick Up Order Label
  PICKUPORDER = 'Do you want to pick up an order?'
  # No Order Found Label
  NOORDERFOUND = 'There is nothing left, boss!'
  # Available Discounts Label
  SOMEDISCOUNTS = 'Press A to get a discount'
  # No Discount Available Label
  NODISCOUNTS = 'No Discount Available'
  # Select a Discount Card or Coupon Label
  SELECTDISCOUNT = 'Choose a Card or Coupon'
  # Apply Discount Label
  APPLYDISCOUNT = 'Discount Applied'
  # Commission Fees Apply Label
  FEESAPPLY = 'Special Fees Apply'
  # Discount Card's Steps Left Label
  STEPSLEFT = " %s steps left."
  # Investment Label...
  INVESTMENT = 'Want to invest in this store?'
  # Share Number Label
  SHARES = 'Share Number'
  # Adquired or Purchased Shares Label
  TOTALSHARES = 'Total Shares'
  # Need a Discount Label
  NEEDADISCOUNT = 'Need a Discount?'
  # Pick Item to be Appraised Label
  APPRAISALMENULABEL = "Appraisal Menu"
  # Appraisal Window Labels
  APPRAISALLABELS = ["Quick Test Cost", "Normal Cost"]
  # Appraisal Options Labels
  APPRAISALOPTIONS = ["Quick Test", "Detailed Test", "Cancel"]
  # Purchase Offer and Haggle Labels
  APPRAISALHAGGLEOPTIONS = ["Accept", "Haggle", "Decline"]
  # Appraisal End Result Labels
  APPRAISALRESULTLABELS = [
    "The item at hand is nothing else but... %s",
    "I think it might be worth some... %s",
    "I've been searching for some %s!",
    "Now I want to make a deal.",
    "What if I make a better offer?",
    "Would you accept some %s?"
  ]
end
# DO NOT EDIT ANYTHING ELSE #
module KyoShopOrders
  @goods = []
  @commissions = []
  @steps = []
  class << self
    attr_accessor :store_id, :goods_id, :goods
    attr_reader :steps, :commissions
    def steps=(val) @steps = val.map {|n| n + rand((n / 2) + 2) } end
    def <<(val)
      @commissions += val
      @commissions = @commissions.flatten
    end
  end
end

class Game_System
  attr_reader :placed_orders, :shop_shares, :shop_favors
  alias kyon_discounts_gm_sys_init initialize
  def initialize
    @placed_orders = {}
    @shop_shares = {}
    @shop_favors = {}
    @placed_orders.default = []
    @shop_shares.default = 0
    @shop_favors.default = 0
    kyon_discounts_gm_sys_init
  end

  def disc_store?(disc_id) !KyoShop::EXCLUSIVESTORES[disc_id] end

  def excl_disc_store?(disc_id)
    exclusive = KyoShop::EXCLUSIVESTORES[disc_id]
    exclusive == $game_variables[KyoShop::STORECODEVARID]
  end

  def check_shares(shop_id)
    results = []
    shares = @shop_shares[shop_id]
    investments = KyoShop::INVESTMENTS[shop_id]
    limits = KyoShop::INVESTMENTS[shop_id].keys.sort
    results = investments.select{|limit| shares >= limit[0] }.map {|r| r[1] }
  end
end

class Game_Party
  attr_reader :discounts
  alias kyon_discounts_gm_party_init initialize
  alias kyon_discounts_gm_party_gain_item gain_item
  def initialize
    @discounts = {}
    kyon_discounts_gm_party_init
  end

  def gain_item(item, n, equip=false)
    kyon_discounts_gm_party_gain_item(item, n, equip)
    return if item == nil or n == 0
    return unless KyoShop::DISCOUNT_IDS.include?(item.id)
    item_id = item.id
    if @discounts[item_id]
      @discounts[item_id] += KyoShop::STEPS[item_id]
      @items[item_id] = 1
    else
      @discounts[item_id] = KyoShop::STEPS[item_id]
    end
  end

  def check_discounts
    unless @discounts.empty?
      for did in KyoShop::DISCOUNT_IDS
        next unless @discounts[did] and @discounts[did] > 0
        return true if $game_system.disc_store?(did)
        return true if $game_system.excl_disc_store?(did)
      end
    end
    for cid in KyoShop::COUPON_IDS
      next unless @items[cid] and @items[cid] > 0
      return true if $game_system.disc_store?(cid)
      return true if $game_system.excl_disc_store?(cid)
    end
    return false
  end

  def decrease_discounts
    KyoShop::DISCOUNT_IDS.each {|n| next unless @discounts[n]
      @discounts[n] -= 1 if @discounts[n] > 0 }
  end

  def discount_cards_expire
    KyoShop::DISCOUNT_IDS.each {|n| @discounts[n] = 0 if @discounts[n] }
  end

  def disc_card_expire(dc_id) @discounts[dc_id] = 0 end
  def item_include?(item_id) @items[item_id] and @items[item_id] > 0 end
end

class Game_Player
  alias kyon_discounts_coupons_gm_player_increase_steps increase_steps
  def increase_steps
    kyon_discounts_coupons_gm_player_increase_steps
    $game_party.decrease_discounts
  end
end

class Game_Interpreter
  alias kyon_discounts_game_inter_comm_302 command_302
  def command_302
    if $game_switches[KyoShop::GOODSSWITCHID]
      KyoShopOrders.store_id = @event_id
      $game_switches[KyoShop::GOODSSWITCHID] = false
      KyoShopOrders.goods = [@params[0,2]]
      loop do
        @index += 1
        if @list[@index].code == 605
          KyoShopOrders.goods << @list[@index].parameters
        else
          return false
        end
      end
    end
    kyon_discounts_game_inter_comm_302
  end
end

class Window_Base
  def appear
    self.active = true
    self.visible = true
  end

  def disappear
    self.active = false
    self.visible = false
  end

  def draw_currency_value(value, x, y, width)
    c = self.contents
    cx = c.text_size(Vocab::gold).width
    c.font.color = normal_color
    c.draw_text(x - 8, y, width-cx-2, WLH, value, 2)
    c.font.color = system_color
    c.draw_text(x, y, width, WLH, Vocab::gold, 2)
  end
end

class Window_KyoShopHelp < Window_Help
  def set_text(text, align=0)
    if KyoShop::DISCOUNT_IDS.include?(KyoShopOrders.goods_id)
      steps = $game_party.discounts[KyoShopOrders.goods_id].to_s
      text = sprintf(KyoShopLabels::STEPSLEFT, steps)
      KyoShopOrders.goods_id = nil
    end
    super(text, align)
  end
end

class Window_Item
  alias kyon_discounts_win_item_up_help update_help
  def update_help
    KyoShopOrders.goods_id = self.item.id
    kyon_discounts_win_item_up_help
  end
end

class AppraiseItemWindow < Window_Selectable
  def initialize
    super(0, 56, 544-160, 280)
    @column_max = 1
    refresh
    self.index = 0
  end

  def refresh
    self.contents.clear
    @data = []
    for n in KyoShop::MYSTERIOUSITEMS
      next if $game_party.item_number(n) == 0
      @data << $data_items[n]
    end
    for i in KyoShop::MYSTERIOUSWEAPONS
      next if $game_party.weapon_number(i) == 0
      @data << $data_weapons[i]
    end
    for i in KyoShop::MYSTERIOUSARMORS
      next if $game_party.armor_number(i) == 0
      @data << $data_armors[i]
    end
    @item_max = @data.size
    return if @item_max == 0
    self.contents = Bitmap.new(width - 32, row_max * 32)
    @item_max.times{|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = case item
    when RPG::Item then $game_party.item_number(item.id)
    when RPG::Weapon then $game_party.weapon_number(item.id)
    when RPG::Armor then $game_party.armor_number(item.id)
    end
    c = self.contents
    x = 4 + index % 2 * (288 + 32)
    y = index / 2 * 32
    rect = Rect.new(x, y, self.width / @column_max - 32, 32)
    c.fill_rect(rect, Color.new(0, 0, 0, 0))
    bit = RPG::Cache.icon(item.icon_name)
    c.blt(x, y + 4, bit, Rect.new(0, 0, 24, 24), 255)
    c.draw_text(x + 28, y, 212, 32, item.name, 0)
    c.draw_text(x + 240, y, 16, 32, ":", 1)
    c.draw_text(x + 256, y, 24, 32, number.to_s, 2)
  end
  def item() @data[@index] end
  def empty?() @data.empty? end
end

class AppraiseInfoWindow < Window_Base
  def initialize(store_id)
    super(384, 112, 160, 224)
    @data = KyoShop::APPRAISALS[store_id]
    @labels = KyoShopLabels::APPRAISALLABELS.dup
    @currency = Vocab.gold
    self.contents = Bitmap.new(width - 32, height - 32)
    refresh
  end

  def refresh
    aw = width - 32
    contents.clear
    contents.font.color = system_color
    contents.draw_text(0, 0, aw, 24, @labels[0])
    contents.draw_text(0, 48, aw, 24, @labels[1])
    contents.draw_text(0, 24, aw, 24, @currency, 2)
    contents.draw_text(0, 72, aw, 24, @currency, 2)
    contents.font.color = normal_color
    contents.draw_text(0, 24, width - 48, 24, @data[:test_cost].to_s, 2)
    contents.draw_text(0, 72, width - 48, 24, @data[:cost].to_s, 2)
  end
end

class AppraiseResultWindow < Window_Base
  def initialize
    super(0, 334, 544, 84)
    @labels = KyoShopLabels::APPRAISALRESULTLABELS.dup
    @currency = Vocab.gold #draw_currency_value(value, x, y, width)
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def refresh(item)
    contents.clear
    result = sprintf(@labels[0], item.name)
    cost = sprintf(@labels[1], item.price) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, cost)
  end

  def ask_favor(item)
    contents.clear
    result = sprintf(@labels[2], item.name)
    contents.draw_text(0, 0, width - 32, 24, result)
    contents.draw_text(0, 24, width - 32, 24, @labels[3])
  end

  def make_offer(overprice)
    contents.clear
    result = sprintf(@labels[5], overprice) + " " + @currency
    contents.draw_text(0, 0, width - 32, 24, @labels[4])
    contents.draw_text(0, 24, width - 32, 24, result)
  end
end

class Window_ShopBuyPlace < Window_Selectable
  attr_accessor :discount
  attr_reader :discounts
  def initialize(shop_goods, discounts=[])
    super(0, 112, 304, 248)
    @shop_goods = shop_goods
    @discount = 0
    @discounts = discounts
    refresh
    self.index = 0
  end

  def deliver(goods)
    @shop_goods = goods
    if goods.size - 1 < @index
      @index = goods.size > 0 ? (@index + goods.size - 1) % goods.size : 0
      update_cursor_rect
    end
    refresh
    self.index = 0
  end

  def item() @data[self.index] end

  def refresh
    @data = []
    for goods_item in @shop_goods
      item = case goods_item[0]
      when 0 then $data_items[goods_item[1]]
      when 1 then $data_weapons[goods_item[1]]
      when 2 then $data_armors[goods_item[1]]
      end
      @data << item if item
    end
    @item_max = @data.size
    create_contents
    @item_max.times {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = $game_party.item_number(item)
    enabled = (item.price <= $game_party.gold and number < 99)
    rect = item_rect(index)
    self.contents.clear_rect(rect)
    draw_item_name(item, rect.x, rect.y, enabled)
    rect.width -= 4
    fee = @discounts.empty? ? @discount : @discounts[index]
    fee = item.price * fee / 100
    self.contents.draw_text(rect, item.price + fee, 2)
  end

  def update_help
    @help_window.set_text(item == nil ? "" : item.description)
  end
end

class Window_ShopNumber
  def initialize(x, y)
    super(x, y, 304, 248)
    @item = nil
    @max = 1
    @price = 0
    @number = 1
    @percent = 0
    @multiplier = 1
  end

  def reset_multiplier
    @multiplier = 1
    @number = 1
    refresh
  end

  def set(item, max, price, percent=0, multiplier=1)
    @item = item
    @max = max
    @price = price
    @number = 1
    @multiplier = multiplier
    @percent = percent
    refresh
  end

  def refresh
    self.contents.clear
    draw_item_name(@item, 0, 96)
    self.contents.font.color = normal_color
    if @multiplier == 1
      cx1, cx2, cx3, cw1, cw2 = [212, 240, 244, 28, 28]
    else
      cx1, cx2, cx3, cw1, cw2 = [196, 202, 212, 68, 64]
    end
    self.contents.draw_text(cx1, 96, 20, WLH, "")
    self.contents.draw_text(cx2, 96, cw1, WLH, @number, 2)
    self.cursor_rect.set(cx3, 96, cw2, WLH)
    if @percent == 0 or @multiplier > 1
      draw_currency_value(@price * @number, 4, 96 + WLH * 2, 264)
      return
    end
    draw_currency_value(@item.price * @number, 4, 72 + WLH * 2, 264)
    draw_percent_value(@percent, 4, 96 + WLH * 2, 264)
    end_price = @item.price + @item.price * @percent / 100
    draw_currency_value(end_price * @number, 4, 120 + WLH * 2, 264)
    draw_price_labels(x - 20, 120, 160)
  end

  def draw_percent_value(value, x, y, width)
    cx = contents.text_size(Vocab::gold).width
    self.contents.font.color = normal_color
    self.contents.draw_text(x - 8, y, width-cx-2, WLH, value, 2)
    text = KyoShopLabels::PRICEDATA[@percent < 0 ? 2 : 1]
    self.contents.draw_text(x + 40, y, width, WLH, text)
    self.contents.font.color = system_color
    self.contents.draw_text(x, y, width, WLH, '%', 2)
  end

  def draw_price_labels(x, y, w)
    self.contents.font.color = normal_color
    self.contents.draw_text(x, y, w, WLH, KyoShopLabels::PRICEDATA[0], 2)
    self.contents.draw_text(x, y + 48, w, WLH, KyoShopLabels::PRICEDATA[3], 2)
  end
end

class Window_ShopPickUp < Window_ShopBuyPlace
  def draw_item(index)
    item = @data[index]
    qty, steps = @shop_goods[index][2..3]
    number = $game_party.item_number(item)
    enough = (number + qty < 100 and steps <= $game_party.steps)
    self.contents.font.color.alpha = enough ? 255 : 128
    y = index * 24
    draw_icon(item.icon_index, 0, y, enough)
    self.contents.draw_text(32, y - 4, 212, 32, item.name, 0)
    self.contents.draw_text(180, y - 4, 88, 32, qty.to_s, 2)
  end
end

class Window_ShopDiscountAlert < Window_Base
  def initialize
    super(0, 360, 304, 56)
    self.contents = Bitmap.new(width - 32, height - 32)
  end

  def set_text(text)
    self.contents.clear
    self.contents.draw_text(0, 0, 272, 24, text)
  end
end

class Window_ShopDiscountCoupon < Window_Selectable
  def initialize
    super(0, 112, 304, 248)
    self.index = 0
    refresh
  end

  def item() @data[self.index] end

  def refresh
    @data = []
    gs = $game_system
    dc_ids = $game_party.discounts.keys.sort
    dc_ids.each {|i| next if $game_party.discounts[i] == 0
      next unless gs.disc_store?(i) or gs.excl_disc_store?(i)
      @data << $data_items[i] }
    KyoShop::COUPON_IDS.each {|i| next unless $game_party.item_include?(i)
      @data << $data_items[i] }
    @item_max = @data.size
    self.index -= 1 if @index > @item_max - 1
    create_contents
    @item_max.times {|i| draw_item(i) }
  end

  def draw_item(index)
    item = @data[index]
    number = $game_party.item_number(item)
    y = index * 24
    rect = Rect.new(4, y, self.width - 32, 32)
    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))
    enabled = $game_party.item_can_use?(item)
    draw_item_name(item, rect.x, rect.y, enabled)
    self.contents.draw_text(32, y, 236, 24, ': ' + number.to_s, 2)
  end

  def update_help
    KyoShopOrders.goods_id = self.item.id
    @help_window.set_text(self.item.description)
  end
end

class Window_ShopStatus
  alias kyon_discounts_win_shop_status_refresh refresh
  def investment=(bool)
    @investment = bool
    refresh
  end

  def refresh
    if @investment
      refresh_investment
      return
    end
    kyon_discounts_win_shop_status_refresh
  end

  def refresh_investment
    self.contents.clear
    shares = $game_system.shop_shares[$game_variables[KyoShop::STORECODEVARID]]
    contents.font.color = system_color
    contents.draw_text(0, 0, 200, 32, KyoShopLabels::TOTALSHARES)
    contents.font.color = normal_color
    contents.draw_text(0, 0, 208, 32, shares.to_s, 2)
  end
end

class Scene_Shop
  def start
    @stage = :main
    @shop_id = $game_variables[KyoShop::STORECODEVARID]
    @goods = $game_temp.shop_goods.dup
    @orders = KyoShopOrders.goods.dup
    update_goods_orders_after_investment
    create_menu_background
    create_command_window
    make_basic_data_windows
    make_shop_windows
    make_discount_order_pickup_windows
    make_appraisal_windows
  end

  def make_basic_data_windows
    @help_window = Window_Help.new
    @gold_window = Window_Gold.new(384, 56)
    @dummy_window = Window_Base.new(0, 112, 544, 304)
    @status_window = Window_ShopStatus.new(304, 112)
    @status_window.visible = false
  end

  def make_shop_windows
    @buy_window = Window_ShopBuyPlace.new($game_temp.shop_goods)
    @buy_window.disappear
    @buy_window.help_window = @help_window
    @sell_window = Window_ShopSell.new(0, 112, 544, 304)
    @sell_window.disappear
    @sell_window.help_window = @help_window
    @number_window = Window_ShopNumber.new(0, 112)
    @number_window.disappear
  end

  def make_discount_order_pickup_windows
    @question_window = Window_ShopDiscountAlert.new
    @question_window.visible = false
    @discount_window = Window_ShopDiscountCoupon.new
    @discount_window.disappear
    @discount_window.help_window = @help_window
    commands = KyoShopLabels::BUYPLACEPICKUP.dup
    commands.pop unless KyoShop::INVESTSTOREIDS.include?(@shop_id)
    @extras_window = Window_Command.new(200, commands)
    @extras_window.x = (544 - 200) / 2
    @extras_window.y = 112
    @extras_window.disappear
    unless KyoShopOrders.goods.empty?
      goods = KyoShopOrders.goods
      @order_window = Window_ShopBuyPlace.new(goods, KyoShopOrders.commissions)
      @order_window.disappear
      @order_window.help_window = @help_window
    end
    @pack_id = [$game_map.map_id, KyoShopOrders.store_id]
    goods = $game_system.placed_orders[@pack_id]
    unless goods
      goods = []
      @no_orders = true
      @extras_window.draw_item(2, nil)
    end
    @pickup_window = Window_ShopPickUp.new(goods)
    @pickup_window.disappear
    @pickup_window.help_window = @help_window
  end

  def make_appraisal_windows
    if (@need_appraisal = KyoShop::APPRAISALS.keys.include?(@shop_id))
      @appraise_item_window = AppraiseItemWindow.new
      @appraise_item_window.visible = false
      @appraise_info_window = AppraiseInfoWindow.new(@shop_id)
      @appraise_info_window.visible = false
      options = KyoShopLabels::APPRAISALOPTIONS.dup
      @appraise_options = Window_Command.new(160, options)
      @appraise_options.disappear
      @appraise_options.x = 240
      @appraise_options.y = 200
      @result_info_window = AppraiseResultWindow.new
      @result_info_window.visible = false
      options = KyoShopLabels::APPRAISALHAGGLEOPTIONS.dup
      @favor_options = Window_Command.new(160, options)
      @favor_options.disappear
      @favor_options.x = 240
      @favor_options.y = 200
    else
      @extras_window.draw_item(3, nil)
    end
  end

  def update_goods_orders_after_investment
    gds = []
    orders = []
    stuff = $game_system.check_shares(@shop_id)
    return if stuff.empty?
    stuff.each {|b| gds += strings_goods_conversion(b[1..-1]) if b[0] == :goods
      orders += string_good_conversion(b[1..-1]) if b[0] == :orders }
    KyoShopOrders.goods = (@orders + orders).sort.uniq
    $game_temp.shop_goods = (@goods + gds).sort.uniq
  end

  def strings_goods_conversion(strings)
    data = []
    strings.each {|string| data << retrieve_item(string) }
    data
  end

  def retrieve_item(string)
    case string[0,1]
    when 'i' then [0, string[1..-1].to_i]
    when 'w' then [1, string[1..-1].to_i]
    when 'a' then [2, string[1..-1].to_i]
    end
  end

  def update_discount_message
    if @buy_window.discount < 0
      text = sprintf(KyoShopLabels::APPLYDISCOUNT, @discount_window.item.price)
    else
      cd = $game_party.check_discounts
      text = cd ? KyoShopLabels::SOMEDISCOUNTS : KyoShopLabels::NODISCOUNTS
    end
    @question_window.set_text(text)
  end

  def terminate
    dispose_menu_background
    dispose_command_window
    @discount_window.dispose
    @extras_window.dispose
    @order_window.dispose
    @pickup_window.dispose
    @question_window.dispose
    @help_window.dispose
    @gold_window.dispose
    @dummy_window.dispose
    @buy_window.dispose
    @sell_window.dispose
    @number_window.dispose
    @status_window.dispose
    if @need_appraisal
      @appraise_item_window.dispose
      @appraise_info_window.dispose
      @appraise_options.dispose
      @result_info_window.dispose
      @favor_options.dispose
    end
    KyoShopOrders.goods.clear
    KyoShopOrders.steps.clear
    KyoShopOrders.commissions.clear
    KyoShopOrders.store_id = 0
    @stage = @shop_id = nil
  end

  def update
    super
    update_menu_background
    @help_window.update
    @gold_window.update
    @number_window.update
    @status_window.update
    case @stage
    when :main then update_command
    when :option then update_extras
    when :purchase then update_purchase
    when :place then update_place_order
    when :pickup then update_pickup_order
    when :discount then update_discount
    when :appraise then update_appraisal
    when :appraise_option then update_appraisal_option
    when :appraise_favor then update_appraisal_favor
    when :sell then update_sell
    when :number then update_number
    end
  end

  def update_command
    @command_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      $scene = Scene_Map.new
      return
    elsif Input.trigger?(Input::C)
      case @command_window.index
      when 0  # buy
        Sound.play_decision
        @command_window.active = false
        @extras_window.appear
        @question_window.visible = true
        update_discount_message
        return @stage = :option
      when 1  # sell
        return Sound.play_buzzer if $game_temp.shop_purchase_only
        Sound.play_decision
        @command_window.active = false
        @dummy_window.visible = false
        @sell_window.appear
        @sell_window.refresh
        return @stage = :sell
      when 2  # Quit
        Sound.play_decision
        $scene = Scene_Map.new
      end
    end
  end

  def update_extras
    @extras_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @extras_window.disappear
      @question_window.visible = false
      @command_window.active = true
      return @stage = :main
    elsif Input.trigger?(Input::C)
      if @no_orders and @extras_window.index == 2
        return Sound.play_buzzer
      end
      shares = $game_system.shop_shares[@shop_id]
      inv_max, inv_price = KyoShop::SHARESMAXMIN
      if @extras_window.index == 4 and inv_max == shares
        return Sound.play_buzzer
      end
      Sound.play_decision
      @extras_window.disappear
      @dummy_window.visible = false
      @status_window.visible = true
      @question_window.visible = @extras_window.index != 3
      update_discount_message
      case @extras_window.index
      when 0 # purchase
        @status_window.item = @buy_window.item
        @buy_window.appear
        @buy_window.refresh
        @last_stage = :option
        return @stage = :purchase
      when 1 # place order
        @status_window.item = @order_window.item
        @order_window.appear
        @question_window.set_text(KyoShopLabels::FEESAPPLY)
        return @stage = :place
      when 2 # pick up order
        @status_window.item = @pickup_window.item
        @pickup_window.appear
        return @stage = :pickup
      when 3 # appraisals
        @appraise_item_window.appear
        @appraise_info_window.visible = true
        @result_info_window.visible = true
        @dummy_window.visible = false
        @command_window.visible = false
        @number_window.visible = false
        @status_window.visible = false
        @help_window.set_text(KyoShopLabels::APPRAISALMENULABEL)
        return @stage = :appraise
      when 4 # investments
        @status_window.investment = @investment = true
        inv_max = [inv_max - shares, $game_party.gold / inv_price].min
        fake_item = RPG::Item.new
        fake_item.name = KyoShopLabels::SHARES
        @price = inv_price
        @number_window.set(fake_item, inv_max, inv_price, 0, 10)
        @number_window.appear
        @question_window.set_text(KyoShopLabels::INVESTMENT)
        @stage = :number
      end
    end
  end

  def update_purchase
    @buy_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @buy_window.disappear
      @status_window.visible = false
      @question_window.visible = false
      @dummy_window.visible = true
      @extras_window.appear
      @status_window.item = nil
      @help_window.set_text("")
      return @stage = :option
    elsif Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @buy_window.item
      return
    elsif Input.trigger?(KyoShop::DISCOUNTBUTTON)
      unless $game_party.check_discounts
        return Sound.play_buzzer
      end
      Sound.play_decision
      @buy_window.disappear
      @discount_window.refresh
      @discount_window.appear
      @question_window.set_text(KyoShopLabels::SELECTDISCOUNT)
      return @stage = :discount
    elsif Input.trigger?(Input::C)
      @item = @buy_window.item
      number = $game_party.item_number(@item)
      shop_max = KyoShop.current_item_max
      if @item == nil or @item.price > $game_party.gold or number == shop_max
        return Sound.play_buzzer
      end
      Sound.play_decision
      max = @item.price == 0 ? shop_max : $game_party.gold / @item.price
      max = [max, shop_max - number].min
      @buy_window.disappear
      discount = @buy_window.discount < 0 ? @buy_window.discount : 0
      @number_window.set(@item, max, @item.price, discount)
      @number_window.appear
      @last_stage = :purchase
      @stage = :number
    end
  end

  def update_place_order
    @order_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @status_window.disappear
      @order_window.disappear
      @extras_window.appear
      @dummy_window.visible = true
      @question_window.visible = false
      return @stage = :option
    elsif Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @order_window.item
      return
    elsif Input.trigger?(Input::C)
      @item = @order_window.item
      @price = @item.price
      percent = KyoShopOrders.commissions[@order_window.index]
      @price += percent * @item.price / 100 if percent > 0
      number = $game_party.item_number(@item)
      shop_max = KyoShop.current_item_max
      if @item == nil or @price > $game_party.gold or number == shop_max
        Sound.play_buzzer
        return
      end
      Sound.play_decision
      max = @price == 0 ? shop_max : $game_party.gold / @price
      max = [max, shop_max - number].min
      @order_window.disappear
      @number_window.set(@item, max, @price, percent)
      @number_window.appear
      @last_stage = :place
      @stage = :number
    end
  end

  def update_pickup_order
    @pickup_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @status_window.disappear
      @pickup_window.disappear
      @extras_window.appear
      @dummy_window.visible = true
      @question_window.visible = false
      return @stage = :option
    elsif Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @status_window.item = @pickup_window.item
      return
    elsif Input.trigger?(Input::C)
      unless (goods = $game_system.placed_orders[@pack_id])
        return Sound.play_buzzer
      end
      current_item = @pickup_window.item
      goods = goods[@pickup_window.index]
      unless current_item and goods[3] <= $game_party.steps
        return Sound.play_buzzer
      end
      Sound.play_decision
      number = goods[2]
      $game_party.gain_item(current_item, number)
      $game_system.placed_orders[@pack_id].delete_at(@pickup_window.index)
      @pickup_window.reload_goods($game_system.placed_orders[@pack_id])
      @last_stage = :pickup
      @stage = :number
    end
  end

  def update_discount
    @discount_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @discount_window.disappear
      @buy_window.appear
      return @stage = :purchase
    elsif Input.trigger?(Input::C)
      Sound.play_decision
      @coupons_allowed = KyoShop::COUPON_IDS.include?(@discount_window.item.id)
      @buy_window.discount = -@discount_window.item.price
      @buy_window.refresh
      @discount_window.disappear
      @buy_window.appear
      update_discount_message
      @stage = :purchase
    end
  end

  def update_appraisal
    @appraise_item_window.update
    if Input.trigger?(Input::UP) or Input.trigger?(Input::DOWN)
      @appraise_info_window.refresh
      return
    end
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @appraise_item_window.disappear
      @appraise_info_window.visible = false
      @question_window.visible = false
      @result_info_window.visible = false
      @result_info_window.contents.clear
      @appraise_options.disappear
      @dummy_window.visible = true
      @command_window.visible = true
      @extras_window.appear
      @help_window.set_text("")
      return @stage = :option
    elsif Input.trigger?(Input::C)
      return Sound.play_buzzer if @appraise_item_window.empty?
      Sound.play_decision
      @appraise_options.appear
      @stage = :appraise_option
    end
  end

  def update_appraisal_option
    @appraise_options.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @appraise_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      data = KyoShop::APPRAISALS[@shop_id]
      price = case @appraise_options.index
      when 0 then data[:test_cost]
      when 1 then data[:cost]
      when 2 then -10
      end
      if price == -10 or $game_party.gold < price
        Sound.play_buzzer
        @appraise_options.disappear
        return @stage = :appraise
      end
      Sound.play_decision
      $game_party.lose_gold(price)
      $game_party.lose_item(@appraise_item_window.item, 1)
      if rand(100) < data[:rate]
        goods = data[:goods]
        favors = $game_system.shop_favors[@shop_id]
        goods += data[:extras] if data[:help_limit] <= favors
        key = goods[rand(goods.size)]
      else
        key = data[:default]
      end
      kind, id = retrieve_item(key)
      new_item = case kind
      when 0 then $data_items[id]
      when 1 then $data_weapons[id]
      when 2 then $data_armors[id]
      end
      if data[:target].has_key?(key)
        @appraise_options.disappear
        @favor_options.appear
        @result_info_window.ask_favor(new_item)
        @target_item = new_item
        @target_key = key
        @target_points = data[:target][key]
        @haggle_enabled = data[:haggle]
        @haggle_max = data[:overprice]
        return @stage = :appraise_favor
      end
      $game_party.gain_item(new_item, 1)
      @result_info_window.refresh(new_item)
      @appraise_item_window.refresh
      @gold_window.refresh
      @appraise_options.disappear
      @stage = :appraise
    end
  end

  def update_appraisal_favor
    @favor_options.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @favor_options.disappear
      return @stage = :appraise
    elsif Input.trigger?(Input::C)
      case @favor_options.index
      when 0
        if @overprice
          Sound.play_shop
          $game_system.shop_favors[@shop_id] += @target_points
          price = @overprice
          @target_points = nil
        else
          Sound.play_decision
          price = @target_item.price
        end
        $game_party.gain_gold(price)
        @overprice = @target_item = nil
      when 1
        return Sound.play_buzzer unless @haggle_enabled
        Sound.play_decision
        @haggle_enabled = nil
        @overprice = rand(@haggle_max) + 1
        @overprice = 25 if @overprice < 25
        @overprice += @target_item.price
        @result_info_window.make_offer(@overprice)
        return
      when 2
        Sound.play_decision
        case @target_item.class
        when RPG::Item then $game_party.gain_item(@target_item.id, 1)
        when RPG::Weapon then $game_party.gain_weapon(@target_item.id, 1)
        when RPG::Armor then $game_party.gain_armor(@target_item.id, 1)
        end
        @target_item = nil
        @favor_options.disappear
      end
      return @stage = :appraise
    end
  end

  def update_sell
    @sell_window.update
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @command_window.active = true
      @dummy_window.visible = true
      @sell_window.disappear
      @status_window.item = nil
      @help_window.set_text("")
      return @stage = :main
    elsif Input.trigger?(Input::C)
      @item = @sell_window.item
      @status_window.item = @item
      if @item == nil or @item.price == 0
        return Sound.play_buzzer
      end
      Sound.play_decision
      max = $game_party.item_number(@item)
      @sell_window.disappear
      @number_window.set(@item, max, @item.price / 2)
      @number_window.appear
      @status_window.visible = true
      @stage = :number
    end
  end

  def update_number
    if Input.trigger?(Input::B)
      Sound.play_cancel
      @number_window.disappear
      if @extras_window.index == 1
        @order_window.appear
        return @stage = :place
      elsif @extras_window.index == 4
        return update_cancel_investment
      end
      case @command_window.index
      when 0
        @buy_window.appear
        return @stage = :purchase
      when 1  # Sell
        @sell_window.appear
        @status_window.visible = false
        return @stage = :sell
      end
    elsif Input.trigger?(Input::C)
      decide_number_input
    end
  end

  def decide_number_input
    Sound.play_shop
    @number_window.disappear
    case @extras_window.index
    when 1
      decide_number_order
      return
    when 4
      decide_number_investment
      return
    end
    case @command_window.index
    when 0  # Buy
      percent = KyoShop.current_price_max
      price = @item.price + @item.price * percent / 100
      price += price * @buy_window.discount / 100
      $game_party.lose_gold(@number_window.number * price)
      $game_party.gain_item(@item, @number_window.number)
      if @coupons_allowed
        @coupons_allowed = nil
        $game_party.lose_item(@discount_window.item, 1)
        @buy_window.discount = 0
        update_discount_message
        @discount_window.refresh
      end
      @gold_window.refresh
      @buy_window.refresh
      @status_window.refresh
      @buy_window.appear
      return @stage = :purchase
    when 1  # sell
      $game_party.gain_gold(@number_window.number * (@item.price / 2))
      $game_party.lose_item(@item, @number_window.number)
      @gold_window.refresh
      @sell_window.refresh
      @status_window.refresh
      @sell_window.appear
      @status_window.visible = false
      @stage = :sell
    end
  end

  def decide_number_order
    percent = KyoShopOrders.commissions[@order_window.index]
    percent += KyoShop.current_price_max
    price = @item.price + @item.price * percent / 100
    $game_party.lose_gold(@number_window.number * price)
    steps = $game_party.steps + KyoShopOrders.steps[@order_window.index]
    order = [nil, @item.id, @number_window.number, steps]
    order[0] = case @item
    when RPG::Item then 0
    when RPG::Weapon then 1
    when RPG::Armor then 2
    end
    unless $game_system.placed_orders[@pack_id]
      @no_orders = nil
      @extras_window.draw_item(2, true)
    end
    $game_system.placed_orders[@pack_id] << order
    @pickup_window.reload_goods($game_system.placed_orders[@pack_id])
    @status_window.refresh
    @gold_window.refresh
    @order_window.refresh
    @order_window.appear
    @stage = :place
  end

  def decide_number_investment
    $game_system.shop_shares[@shop_id] += @number_window.number
    update_goods_orders_after_investment
    @order_window.deliver(KyoShopOrders.goods)
    @buy_window.deliver($game_temp.shop_goods)
    @gold_window.refresh
    update_cancel_investment
  end

  def update_cancel_investment
    @investment = nil
    @status_window.investment = nil
    @status_window.visible = false
    @question_window.visible = false
    @dummy_window.visible = true
    @number_window.reset_multiplier
    @number_window.disappear
    @extras_window.appear
    @stage = :option
  end
end

Happy Script Testing!? Confused


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-18-2019

Yeah, bump...

Even if I really hate the fact that I didn't get much feedback lately concerning bugs or missing features, I have uploaded the latest versions of the KyoDiscounts XP, VX and ACE scripts. All of them have reached the 1.5.0 milestone officially!

Of course, there is always some room for bugs... Confused but I HOPE I will get some reports if that were the case here. Confused


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-27-2019

Another bump... hurrah... Sarcasm + Confused

I have gladly Sarcasm published the latest version of KyoDiscounts XP, even if I have not received any full or partial bug report of the previous one...  Sarcasm + Confused

Since version 1.6.0 you need to place the contents of kyodiscountsxptool.rb in a separate section in the script editor, right above KyoDiscounts XP. It is a temporary script that might be called a parser since it reads the template TXT files, following the shop item list any-number.txt naming convention, used in the creation of the custom price increases and decreases. That tool is not supposed to be distributed with your closed demo or finished game project!

My script would be lucky if anybody tests it any time soon... Confused


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-28-2019

A Traveling BUMP!

Guess what people? I have traveled in time! Laughing And I have foreseen the XP version of my script did include a bug, a missing method alias feature to be honest with you. Confused Once I returned to our timeline, I have managed to fix it, hopefully... You know, I don't have any sonic screwdriver to make anything work as I just expected. Laughing + Tongue sticking out


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-29-2019

A Revamped BUMP But the Appraiser Does Not Know What is a Flux Capacitor!

After discussing with Maracuyá, actually getting tired of his suggestions that almost sound like actual demands Sarcasm + Confused , I have redesigned the Appraisal section of KyoDiscounts XP. It has now reached the 1.6.8 milestone! Shocked

One of the benefits is that you can now specify which item or weapon or armor will trigger a specific result during the appraisal stage, like revealing the unknown stone was some ultra powerful weapon or just a fur ball. Laughing  By the way, after n attempts you might get surprised. You see, after the player has reached an amount of points by bringing in some interesting artifacts, the appraiser might be able to appraise extra goods. I guess it simulates the appraiser's ability to increase his own experience. Happy


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-30-2019

A Quickly Parsed BuMp!

Well, I have uploaded a new version of KyoDiscounts XP, guys! Shocked It has reached the 1.6.10 milestone already! I have updated the main script as well as the kyodiscountsxptool.rb parser, yeah, the one you open in a text editor just like any TXT file you have found before.

So far you could configure the STORECODEVARID constant to define the in-game variable that would hold the Store ID you need for Exclusive Stores or shops where investors are welcome or those stores that offer their appraisal services. Now you could use a script call instead. (I think I have reinstalled this call after its long absence. Blame Maracuyá for it!)

The script call would be...
KyoShop.id = 100

Oh and I have created two new directories, namely Appraisals and PriceChanges. They will hold all of the TXT configuration files needed by KyoDiscounts. During development you will need to run the parser alias kyodiscountsxptool.rb to make new rxdata files located in the Data directory. Before your game is ready for distribution, remove the parser and the temporary Appraisals and PriceChanges folders or move them to another location. (You do not want your players to cheat via modifying the TXT files! Laughing )

By the way, now you can prevent the player from selling either discount cards or coupons at stores at any time.

KyoShop.no_card_sale = true
KyoShop.no_coupon_sale = true


Or use false to allow their sales once again.


RE: KyoDiscounts XP VX, ACE MV - kyonides - 01-31-2019

Some Bump alias Maintenance Update

Guess, what? I have found a couple of minor bugs and have thought I had to fix them. A few moments ago I finished uploading the new version, namely the brand new 1.6.11. It also includes a new window that will show common weapon or armor stats in the purchase stage if you press some specific button you can configure in the KyoShop module as usual.

I will not wish you some happy testing because I know for sure most of you never test scripts. =_=