############################################
#                                          #
#          PLAYING CARDS SCRIPT            #
#                                          #
#       v1.0 for RPG Maker VX Ace          #
#                                          #
# Created by Jason "Wavelength" Commander  #
#                                          #
############################################

# "Never lost a fair game... or played one."
#                                     ~ Twisted Fate, League of Legends


############################################
#                                          #
#           ABOUT THIS SCRIPT              #
#                                          #
############################################

# This script allows you to pick random cards from a deck,
#        store information about the card you chose to an
#        easily-accessible variable, and display the chosen
#        card to the player (via text, pictures, or both).
#        You can also prevent that card from being chosen again
#        until you "shuffle" the deck.

# Here's what the Playing Cards script allows you to do that
#        you couldn't otherwise do with simple eventing:
#
#       * Remove cards from the deck as they are drawn, if desired
#
#       * Get information about the value and suit of a
#         randomly-drawn card using a single-line script call
#
#       * Show a picture of that randomly-drawn card using a
#         single-line script call
#
#       * Show the name (or value) of that randomly-drawn card
#         in a single message box
#
#       * Automatically convert a playing card's value for use in
#         a minigame; e.g., making all Jacks, Queens, & Kings worth
#         10 when playing Blackjack
#
#       * Save hundreds or even thousands of event commands worth
#         of effort and processing power when making card games
#
#       * Create your own deck of cards with different numbers or
#         suits (or even get rid of numbers or suits altogether),
#         and use the functionality of this script for your deck
#
# And don't forget that the logic underlying the script can be
#       useful in all sorts of RNG-type applications, not just
#       card games!

# This script is compatible with all other scripts.    


############################################
#                                          #
#              TERMS OF USE                #
#                                          #
############################################

#  Free to use for non-commercial projects - just credit me

#  Contact me first before using in commercial projects

#  You may freely share or modify this script, but you cannot
#       sell it (even if modified) without my written permission

#  Please preserve the header (with version #) and terms of use;
#       besides that, feel free to remove any commenting you please


############################################
#                                          #
#         HOW TO USE THIS SCRIPT           #
#                                          #
############################################


# First, set values for the variables in the "Playing Cards Setup"
#       section below.  If you want to change the composition of
#       the deck, change the way that card IDs are converted to
#       usable values, or show pictures of cards that are selected,
#       you should also visit the "Advanced Setup" section below.

# You can use a single-line script call in the Event Editor (or
#       combine several script calls into a single script block)
#       to draw a card, show a picture of the last card drawn,
#       or change the cards available in the deck.
#
# Here are the script calls that this script provides:
#
#   1. $game_party.draw_card(game)
#
#   Randomly draws a card from the deck, and automatically stores
#   information about the card that was drawn.  If the "Removal"
#   option is set to True, the drawn card is removed from the deck.
#   * "game" is an optional integer that specifies which "Conv_Value"
#   array (if any) will be used to automatically convert the value of
#   the card.
#   Aliases for draw_card: d_c
#
#   2. $game_party.show_card(picture_number, x, y)
#
#   Shows a picture of the last card that was drawn.  If you are using
#   this command, you will need to import a picture for each card into
#   your Graphics/Pictures folder.
#   * The name of the picture should be Cards_1.png, Cards_2.png, etc.,
#   unless you have changed the Pic_prefix or Pic_extension options.
#   * "picture_number", "x", and "y" are all optional integers that specify
#   the Picture Number, x-coordinate, and y-coordinate for the picture (if
#   not provided, the default values will be used).
#   * To erase the picture of the card, simply use the "Erase Picture" event
#   command and use the picture_number that you chose here.
#   Aliases for show_card: s_c

#   3. $game_party.pullcard(card)
#
#   Removes a card from the deck so that it may not be drawn until added
#   back into the deck.
#   * The "card" integer is used to specify which card to remove.  For
#   example, in a standard deck, $game_party.pullcard(1) will remove the
#   2 of Spades from the deck, while $game_party.addback(52) will remove
#   the Ace of Hearts.
#   Aliases for pullcard: pull_card, removecard, remove_card

#   4. $game_party.addback(card)
#
#   Adds a card into the deck so that it may once again be drawn.
#   * The "card" integer is used to specify which card to add.
#   Aliases for addback: add_back, addcard, add_card

#   5. $game_party.shuffle
#
#   Adds all cards back into the deck.  You'll probably want to use
#   this command at the beginning or end of a hand in most games.
#   Aliases for shuffle: (none)

#   6. $game_party.cards_remaining(variable)
#
#   Returns the number of cards remaining in the deck.  This could
#   be useful if you need your minigame to shuffle the deck when there
#   are a certain number of cards (or no cards) remaning.
#   * "variable" is an optional integer that specifies a Variable to
#   which save the number of cards remaining, in case you need to use
#   it later.
#   Aliases for cards_remaining: c_r

# After using the "draw_card" method, you will have access to the
#       card's ID (position in the deck), value, suit.  Use whatever
#       variable you specified in Card_holder below to access the
#       card's ID, Value_holder for its value, and Suit_holder for
#       its suit.  (Name can also be accessed, if necessary, using
#       $game_actors[10].name - replace 10 with the value you specified
#       for Name_holder.)  If you need to preserve the values, simply
#       use event commands to copy th variables' values before using the
#       draw_card method again.

# You can use \V[x] (for Card Holder, Value Holder, and Suit Holder)
#       and \N[x] (for Name Holder) inside Message Boxes to show the
#       ID, Value, Suit, or Name of the last card that was drawn.

# If you try to draw a card when there are no cards left in the deck,
#       a special value -999 will be displayed for Card ID/Value/Suit
#       and a special value "OUT OF CARDS" will be displayed for Card Name.
#       In general, you should design your game so that cards are shuffled
#       as soon as (or before) the last card is drawn from the deck.


module Cards

############################################
#                                          #
#          PLAYING CARDS SETUP             #
#                                          #
############################################

# *** You must correctly set these values for the script to work properly. ***

# Choose which variables and actor names will be used to store information
#       about the last card selected.  For example, if you want Variable 208
#       to store information about about the Suit of the card that was chosen,
#       then change the Suit_holder from 43 to 208.

# These variables will come in handy as you can use simple eventing logic to
#       make things happen based on the value, suit, or identity of the card
#       that was chosen after the draw_card call.

# * Card_holder is the variable used to hold info about the ID ("position"
#       in the deck) for the chosen card.  (In a standard deck of playing
#       cards, the 2 of Spades has a Card_Holder value of "1", the 2 of
#       Clubs has a value of "2", the Ace of Spades "49", and the Ace of
#       Hearts "52".)

  Card_holder = 41

# * Value_holder is the variable used to hold info about the "number" on
#       your card.  (In a standard deck of playing cards, the 2 of Spades
#       and 2 of Clubs both have a Value_holder value of "1", the 3 of
#       Spades and the 3 of Clubs have a Value_holder value of "2", and
#       the Ace of Spades and Ace of Hearts have a value of "13".  If you
#       want to change these values)

  Value_holder = 42

# * Suit_holder is the variable used to hold info about the suit of your
#       card.  (In a standard deck of playing cards, the 2 of Spades and
#       Ace of Spades both have a Value_holder value of "1", while the
#       2 of Hearts and Ace of Hearts both have a value of "4".)

  Suit_holder = 43

# * Name_holder is the ID of the ACTOR in your database whose name is used
#       to hold the name of your card (e.g. "the 7 of Diamonds").  The
#       reason this is stored in a name is to make it easy to display the
#       name of the chosen card in a message box.  Make sure you choose
#       an Actor ID of an Actor that exists in your database, but that you
#       are not using anywhere in your game.

  Name_holder = 10
  
# Leave the Removal option as 'true' if cards should be removed from the deck
#       once they have been drawn.  (They can be added back at any time using
#       "shuffle" or "addback" method calls.)  Change this option to 'false'
#       if you want cards to remain in the deck even after they are drawn.

  Removal = true
  
############################################
#                                          #
#             ADVANCED SETUP               #
#                                          #
############################################
  
# If you've done the above correctly, this script will work properly for a
#       standard 52-card deck of playing cards.  Everything from here on is
#       entirely optional and is used to change the composition of your game's
#       deck of cards or customize the system to your liking.
  
# Choose the number of cards that you want in your deck.

  Deck_size = 52

# Enter the names of suits in your deck.  The size of this array is
#       not fixed at 4 - you can add or remove suits as you please.

  Suits = ["Spades","Clubs","Diamonds","Hearts"]
  
# Enter the names of values of cards in your deck, such as "Ace",
#       "2", and "3".  The size of this array is not fixed at 13 -
#       you can add or remove values as your please.

  Values = ["2","3","4","5","6","7","8","9","10","Jack","Queen","King","Ace"]
  
# In some games, you may want to automatically convert the value of a card
#       before you return it to the Value_holder variable.  Support for doing
#       this in up to five games is given here, and you can add more if you
#       want by modifying the draw_card method in my script.

# A good example of when you want to do this is to create a Blackjack game.
#       I have set this up for you here using Conv_Value_3, so if you want
#       to get the "Blackjack Value" of a card, simply pass in "3" as the
#       first argument of the draw_card script call.

# IMPORTANT: Be sure that these arrays have the same length as your "Values"
#       array above.

  Conv_Value_1 = [1,2,3,4,5,6,7,8,9,10,11,12,13]
  Conv_Value_2 = [1,2,3,4,5,6,7,8,9,10,11,12,13]
  Conv_Value_3 = [2,3,4,5,6,7,8,9,10,10,10,10,11]
  Conv_Value_4 = [1,2,3,4,5,6,7,8,9,10,11,12,13]
  Conv_Value_5 = [1,2,3,4,5,6,7,8,9,10,11,12,13]
  
# Choose defaults for whether a card should be displayed to the player once
#       it's chosen, how many seconds to display it for which Picture Number
#       the card occupies, and the x and y coordinates to display the card at.

# If you choose to use the "show_card" method, these variables define the
#       default Picture Number, x-coordinate, and y-coordinate that will be
#       used if you don't explicitly define these values when calling the
#       method.

  Picture_id = 21 # NOTE: This is "Number" on the 'Show Picture' event command.
  Default_x = 197
  Default_y = 103

# If you choose to use the "show_card" method to show pictures of the selected
#       card, specify here how you will name the pictures.  If you don't change
#       these options, you will want to name your cards "Cards_1.png",
#       "Cards_2.png", etc.  Be sure your pictures are in the Graphics/Pictures
#       folder.

  Pic_prefix = "Cards_"
  Pic_extension = ".png" # NOTE: This should be ".png" or ".jpg"

# Design the template for naming your cards using the "namestring" variable.
#       NOTE: If you don't understand what's going on here, I strongly advise
#       leaving this option alone.  But if you do know what you're doing, you
#       can use this method to hard-code display strings such as "A Joker" if
#       a certain combination of value and suit is picked.

  def self.makename(value, suit)
    namestring = ("the " + value + " of " + suit)
    return namestring
  end

end

############################################
#                                          #
#               ICKY CODE!                 #
#                                          #
############################################

# Everything from here on represents the inner workings of the script.
#       Please don't alter anything from here on unless you are an
#       advanced scripter yourself (in which case, have at it!)  

class Game_Party < Game_Unit
  
  #--------------------------------------------------------------------------
  # * Public Instance Variables
  #--------------------------------------------------------------------------
  attr_reader   :deck                 # Array of Cards available for the Draw

  #--------------------------------------------------------------------------
  # * Object Initialization
  #--------------------------------------------------------------------------
  alias :init_with_deck :initialize
  def initialize
    init_with_deck
    shuffle
  end
  
  #--------------------------------------------------------------------------
  # * "Shuffle" the deck so that all cards are available for the Draw
  #--------------------------------------------------------------------------
  def shuffle
    @deck = []
    for i in 1..Cards::Deck_size
      deck.push(i)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Add a specific card back into the array of Available Cards
  #--------------------------------------------------------------------------
  def add_back(card)
    @deck.push(card)
    @deck.sort!
  end
  
  #--------------------------------------------------------------------------
  # * Other acceptable ways to call "add_back"
  #--------------------------------------------------------------------------
  def addback(card)
    add_back(card)
  end
  def add_card(card)
    add_back(card)
  end
  def addcard(card)
    add_back(card)
  end
  
  #--------------------------------------------------------------------------
  # * Remove a specific card from the array of Available Cards
  #--------------------------------------------------------------------------
  def pull_card(card)
    @deck.delete(card)
  end
  
  #--------------------------------------------------------------------------
  # * Other acceptable ways to call "pull_card"
  #--------------------------------------------------------------------------
  def pullcard(card)
    pull_card(card)
  end
  def remove_card(card)
    pull_card(card)
  end
  def removecard(card)
    pull_card(card)
  end
  
  #--------------------------------------------------------------------------
  # * Draw a Random Card out of cards that have not already been Drawn
  #--------------------------------------------------------------------------
  def draw_card(autoconv_type = 0)
    if @deck.size <= 0 # A catch in case all cards have been drawn
      $game_variables[Cards::Card_holder] = -999
      $game_variables[Cards::Value_holder] = -999
      $game_variables[Cards::Suit_holder] = -999
      $game_actors[Cards::Name_holder].name = "OUT OF CARDS"
      return
    else
      pick = (rand(@deck.size)).to_i
      chosen = deck[pick]
      if Cards::Removal == true
        deck.delete_at(pick)
      end
    end
    $game_variables[Cards::Card_holder] = chosen
    $game_variables[Cards::Value_holder] = convert(chosen, 1)
    $game_variables[Cards::Suit_holder] = convert(chosen, 2)
    $game_actors[Cards::Name_holder].name = convert(chosen, 3)
    divisor = (Cards::Suits).size
    case autoconv_type
    when 1
      $game_variables[Cards::Value_holder] = Cards::Conv_Value_1[((chosen - 1) / divisor).to_i]
    when 2
      $game_variables[Cards::Value_holder] = Cards::Conv_Value_2[((chosen - 1) / divisor).to_i]
    when 3
      $game_variables[Cards::Value_holder] = Cards::Conv_Value_3[((chosen - 1) / divisor).to_i]
    when 4
      $game_variables[Cards::Value_holder] = Cards::Conv_Value_4[((chosen - 1) / divisor).to_i]
    when 5
      $game_variables[Cards::Value_holder] = Cards::Conv_Value_5[((chosen - 1) / divisor).to_i]
    else
    end
  end
  
  #--------------------------------------------------------------------------
  # * Provide a more concise way to call the Draw Card method
  #--------------------------------------------------------------------------
  def d_c(autoconv_type = 0)
    draw_card(autoconv_type)
  end
  #--------------------------------------------------------------------------
  # * Convert a Card Position into a Value, Type, or Name.
  #--------------------------------------------------------------------------
  def convert(chosen, type)
    divisor = (Cards::Suits).size
    value = Cards::Values[((chosen - 1) / divisor).to_i]
    suit = Cards::Suits[((chosen - 1) % divisor)]
    name = Cards.makename(value, suit)
    case type
    when 1
      return ((((chosen - 1) / divisor).to_i) + 1)
    when 2
      return (((chosen - 1) % divisor) + 1)
    when 3
      return name
    end
  end
  
  #--------------------------------------------------------------------------
  # * Display the Chosen Card onscreen.
  #--------------------------------------------------------------------------
  def show_card(pic_id = -999, x_coord = -999, y_coord = -999)
    chosen = $game_variables[Cards::Card_holder]
    pic_string = Cards::Pic_prefix + chosen.to_s + Cards::Pic_extension
    if pic_id == -999; pic_id = Cards::Picture_id; end
    if x_coord == -999; x_coord = Cards::Default_x; end
    if y_coord == -999; y_coord = Cards::Default_y; end
    unless chosen == -999
      $game_map.screen.pictures[pic_id].show(pic_string, 0, x_coord, y_coord, 100, 100, 255, 0)
    end
  end
  
  #--------------------------------------------------------------------------
  # * Provide a more concise way to call the Show Card method.
  #--------------------------------------------------------------------------
  def s_c(pic_id = -999, x_coord = -999, y_coord = -999)
    show_card(pic_id, x_coord, y_coord)
  end
  
  #--------------------------------------------------------------------------
  # * Add a specific card back into the array of Available Cards
  #--------------------------------------------------------------------------
  def cards_remaining(slot = -999)
    unless slot == -999
      $game_variables[slot] = @deck.size
    end
    return @deck.size
  end
  
  #--------------------------------------------------------------------------
  # * Provide a more concise way to call the Cards Remaining method.
  #--------------------------------------------------------------------------
  def c_r(slot)
    cards_remaining(slot)
  end
  
end
