Jump to content
pencilcase27

CardGame inspired skill and battle system

Recommended Posts

pencilcase's

 

CardGame Skill/Battle System

 

 

 

This script changes the way actors aquire and use skills. Instead of each actor having an own set of skills, the party now has a card collection of different cards, each card representing a different skill. With this collection, each actor can now create a custom deck to use in battle.
 
If you have ever played a card game like Magic: the Gathering or Yu-Gi-Oh you can imagine how combat works. Actors take turns and draw skills, then use as many skills as they want/can until they choose to end their turn. Once all actors are done, the enemy troop moves regularly.
 
This scrip however is not a tool to make a "real" cardgame. Its goal is to combine card/deckbuilding elements with classic rpg combat and not to create a YuGiOh spin-of.
 
 
The script replaces the skill command in the menu with a deck command, that grands access to the deck building scene:
 
1PM5ESe.png
 Actors Deck                        Collection                           Selected Card + Help Window
 
From here, you can add and remove cards from your actors deck. It has also an inbuild filter to show only certain cards in the players collection.
 
 
As you can see, skills are no longer visualized only by a symbol and a name, but a real card. This card shows Name, MP/TP cost, description text, card number and two additional features - a type and a rarity (at least thats what I called them, they are nothing but a symbol and a word, their meaning is your choice). The color of the cards background can be determined via the damage element:
 
qGcWQ6T.png   TPIZqac.png   R3WPdpv.png
  Doesn't matter which one of them you choose, they all hurt.
 
 
If you want your cards to look even more special, you can choose to draw them with a custom window skin:
 
8E0zvgy.png            FlaefrH.png   ZoHZ3dm.png
 This one I have drawn myself, is               Those and other excellent window skins you can find at
 it not the most beautifull piece                  http://windowskins.rpgmakertimes.info/
 of art you have ever seen?
 
 
And if you don't like my layout, just use a custom card image:
 
CuLRJeD.png
This image was created with the MagicSetCreator.
 
 
The battle scene also got a makeover to display cards instead of the help window:
 
5HasKlc.png
  It also adds a indicator of the actors remaining deck cards. Poor Terence ran out of cards to draw...
 
 
For more detailed information what the script does, read trough it's instructions and options.
 
Shop Addon (v1.01): http://pastebin.com/P6aRTyxx
Addon for special states/equips (v1.00): http://pastebin.com/2dyeGWEP
Booster:

Many people asked me to add bosster. but since boosters are not cards, but consumable items that give you cards, it's possible to create booster with a common event bound to an item. Here is an example how the scriptcall in this common event would look like:
#-- The skill id's of possible cards your booste can give you. The the more often
#-- a card is in that array, the more likely it is to get this card.
possible_cards = [4,5,6,7,8,9,10,11,12,13,13,13,13]

#-- How many cards does the booster contain?
n = 5

#-- The text that is shown when you recive a card. (+ card name)
text = "You got: "


n.times do
 card = possible_cards.sample
 add_card_to_coll(card)
 msg = text + $data_skills[card].name  # If you don't want to
 $game_message.add(msg)                # show a message, delete
 wait_for_message                      # these three lines
end
Two pictures on how to set up an booster item. It's just an example, you can add a few mor things, like a sound effect or something:
N3U23iV.png
 
u4ATeeK.png

 
 
Terms of Use:
Free for not commercial use, as long as credits are given.
Please do not use this script in commercial projects.
 
Demo:
I won't release a demo. Please read script instructions carefully. If you have any questions or feedback on how to make them more clear, please contact me via pm or in this thread.
 
Thanks:
DiamondandPlatinum3 - without his tutorials this would have not been possible.
Yanfly - looking through his code helped a lot whenever I was lost, especially the Instant Cast script.
And the nice fellas in this community who answerd my questions, especially our code fary who got me interessted in all this mess that consumed the last week of my life... :P
 
Final note:
The main reason I wrote this script was not because I needed a card game script, but because I wanted to learn rgss3 and ruby. This means that this is by far my biggest script so far and if you choose to use it, expect to find the one or other bug. But I ensure you, I am more than eager to fix every single one of them!
Also I found myself enjoying reading through other scripts, seeing how others do this and that. And if any scripter out there feels the same and wants to take a look at my project, I would appreciate any feedback, and even if the only feedback you can give is: "Script is a mess, I don't understand a word, pls re-write!"
 
(http://imgur.com/a/Gp4Oy#0   Imgur album of most of the the pictures in case they won't show up for any reason.)
 
EDIT: Since it's creation, many people brought up a whole bunch of ideas on how to improve the script. I'd like to thank the people over the next three pages in this thread for delivering so much feedback on this project. I love you <3
Edited by pencilcase27
  • Like 10

Share this post


Link to post
Share on other sites

Very, very interesting script you've created here, Pencilcase27. I'm requesting a demo just so that I can dive into the action and see if I want to replace the battle system I'm currently using with this or not. It looks and sounds pretty fun.

Share this post


Link to post
Share on other sites

Very, very interesting script you've created here, Pencilcase27. I'm requesting a demo just so that I can dive into the action and see if I want to replace the battle system I'm currently using with this or not. It looks and sounds pretty fun.

Meh, you guys are way too fast :) The only thing I could provide right now is the kinda messy version I developed the script in, and I'd rather not do that. It's 23 pm at my place and I really need some sleep, so I hope you do not mind to wait till tomorrow. Sorry :/

Edited by pencilcase27

Share this post


Link to post
Share on other sites

 

pencilcase's

 

CardGame Skill/Battle System

 

 

 

This script changes the way actors aquire and use skills. Instead of each actor having an own set of skills, the party now has a card collection of different cards, each card representing a different skill. With this collection, each actor can now create a custom deck to use in battle.
 
If you have ever played a card game like Magic: the Gathering or Yu-Gi-Oh you can imagine how combat works. Actors take turns and draw skills, then use as many skills as they want/can until they choose to end their turn. Once all actors are done, the enemy troop moves regularly.
 
 
The script replaces the skill command in the menu with a deck command, that grands access to the deck building scene:
 
5nm9vIv.png
 Actors Deck                        Collection                           Selected Card + Help Window
 
From here, you can add and remove cards from your actors deck. It has also an inbuild filter to show only certain cards in the players collection.
 
 
As you can see, skills are no longer visualized only by a symbol and a name, but a real card. This card shows Name, MP/TP cost, description text, card number and two additional features - a type and a rarity (at least thats what I called them, they are nothing but a symbol and a word, their meaning is your choice). The color of the cards background can be determined via the damage element:
 
qGcWQ6T.png   TPIZqac.png   R3WPdpv.png
  Doesn't matter which one of them you choose, they all hurt.
 
 
And finally, if you want your cards to look even more special, you can choose to draw them with a custom window skin:
 
8E0zvgy.png            FlaefrH.png   ZoHZ3dm.png
 This one I have drawn myself, is               Those and other excellent window skins you can find at
 it not the most beautifull piece                  http://windowskins.rpgmakertimes.info/
 of art you have ever seen?
 
 
The battle scene also got a makeover to display cards instead of the help window:
 
5HasKlc.png
  It also adds a indicator of the actors remaining deck cards. Poor Terence ran out of cards to draw...
 
For more detailed information what the script does, read trough it's instructions and options. If anyone asks for it, I could upload a demo, too.
 
Script:


#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#                           CARDGAME SKILL/BATTLE SYSTEM
#                               Author: pencilcase27
#                               Version:       v1.00
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#
#                                  Description
#
# This script changes the way actors aquire and use skills. Instead of each
# actor having an own set of skills, the party now has a card collection of
# different cards, each card representing a skill. Out of this collection, each
# actor can now create a custom deck.
# In battle, actors will act in turns. They draw cards and, while an actor is
# active, he can play as many cards and items as he wants, as long as he has
# the recources to do so. Once he is done, he can end his turn and the next
# actor becomes active. When every actor finished his or her turn, the enemys
# use their skills normal.
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#
#
#                                  Script Calls
#
# $game_party.add_card_to_album(id1, id2, id3, ...)
# Adds cards of the given skill id to your collection
#
#                                   Notetags
#
# 'card id', 'card type' and 'card rarity' define the propertys of a card
# and should be used for every card.
#-------------------------------------------------------------------------------
# <card id: x> 
# The card id of the skill. Each card must have a unique id.
# Important: Every time this script uses the word id, it refers to the skills
# id, not the card id! The card id is only used to sort cards!
#
# <card type: x>
# The type of the card. Different types can be defined below.
#
# <card rarity: x>
# The rarity of the card. Different raritys can be defined below.
#
#
#
#
# 'draw cards' and 'select cards' are special, card related skill effects and
# are only to be used if you want a card to have this effect.
#-------------------------------------------------------------------------------
# <draw cards: x, y, target>
# This skill has a y% probability to draw x cards. Can be used multiple times. 
# Targets can be either targ or self. self will aim this effect only at the
# user, while targ will effect every target the skill hits.
#
# Example:
#
# <draw cards: 2, 100, self>
# <draw cards: 1, 50, self>
# Draw two and 50% of the time three cards.
#
#
# <card select: x, location, destination, type>
# Selects the top x cards from location, does something based on type and puts
# them back to destination.
# Location and destination can be hand, deck and grav (=grave). If x = 0, it
# takes the entire location.
# Types are look, sort and take.
#  'look' simply looks at those cards and puts them back in the same order.
#  'sort' allows to sort the cards before putting them back.
#  'take' lets you choose one of the cards to take it to your hand, then puts
#   the rest back. If the destination is the deck, it will be shuffled.
# Cannot be used multiple times per card and has to be placed beneath
# everything else!
#
# Example:
#
# <card select: 5, deck, deck, look>
# Look at the top 5 cards of your deck.
#
# <card select: 3, grav, deck, take>
# Look at the top 3 cards of your grave, take one to your hand and shuffle
# the other two back into your deck.
#
# <card select: 1, grav, hand, look>
# Draw the top card of your grave.
#
# <card select: 0, hand, deck, sort>
# Put your entire hand at the top of your deck in any order.
#
# <card select: 0, deck, deck, take>
# Search your deck for a card and put that card into your hand. Then shuffle
# your deck.
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#
#                                  Damage Formula
#
# Those commands can be used for a skills damage formula. Make sure they
# always target an actor, since they won't have any effect on enemys.
# 
# revive_grave(true/false)   
# Shuffles your grave in your deck without penalty. If the argumet is true,
# a message will be shown.
#
# revive_penalty
# Causes the revive penalty to happen.
#
# shuffle_deck(true/false)
# Shuffles the actors deck. If the argument is true, a sound will be played.
#
# card_to_grave?(skill_id)
# Tries to throw the skill with the given ID to the grave. Returns true, if it's
# successfull and false otherwise.
#
# throw_cards(n)
# Throws n random cards to the grave. If n = 0, the actor will loose all cards.
#
#
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
module PC27
  module CG
#-------------------------------------------------------------------------------
#
#                                   Options
#
#-------------------------------------------------------------------------------


 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 #                                   Vocab
 #------------------------------------------------------------------------------
 # DECK             - Name of the actors Deck
 # HAND             - Name of the actors Hand
 # GRAVE            - Name of the actors Grave
 # COLLECTION       - Name of the Card Collection
 # END_TURN         - Name of the command that will end a players turn
 # DRAW_MESSAGE     - Text that appears when an actor draws a card. Displayed
 #                    as "Actor Name" + DRAW_MESSAGE + "Skill Name"
 # REVIVE_MSG       - Text that appears when you revive your grave
 # CARD_HELP_WINDOW - Help text shown in the deck scene (Use \n to break line)
 # FILTER_TEXT      - First part of the text inside of the filter window
 # F_...            - Second part of the text inside of the filter window
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  DECK              = "Deck"
  HAND              = "Hand"
  GRAVE             = "Grave"
  COLLECTION        = "Collection"
  END_TURN          = "End Turn"
  DRAW_MESSAGE      = "draws"
  REVIVE_MSG        = "'s grave was revived"
  CARD_HELP_WINDOW  = "Select: move card\nX(A): open filter"
  FILTER_TEXT       = "Filter by "
  F_ELEMENT         = "element: "
  F_TYPE            = "type:    "
  F_RARITY          = "rarity:  "
 
  
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 #                                  Gameplay
 #------------------------------------------------------------------------------
 # USE_ITEMS        - Are items in battle enabeld?
 # START_CARDS      - Cards drawn in Turn 1
 # MAX_DECK_SIZE    - Maximum size of a players deck
 # MAX_SAME_CARDS   - Maximum amount of same cards in each deck
 # DECK_EMPTY       - What happens if an actor tries to draw a card but has an
 #                    empty deck?
 #                    1 -> The actor dies
 #                    2 -> The actor dies if his grave is empty, too. If it
 #                         isn't, he revives his grave, meaning he shuffles his
 #                         grave back into his deck. Revive penalty is applied
 #                    3 -> Like 2, but the actor won't die if the grave is empty
 # REVIVE_PENALTY   - The revive penalty. Types are :hp, :mhp, :mp and :mmp.
 #                    The actor will lose either hp or mp, based on its current
 #                    or maximum value
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  USE_ITEMS         = true
  START_CARDS       = 5
  MAX_DECK_SIZE     = 30
  MAX_SAME_CARDS    = 4
  DECK_EMPTY        = 1
#                     [percent, type]
  REVIVE_PENALTY    = [     50,  :hp]

  
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 #                              Icons and Sound
 #------------------------------------------------------------------------------
 # DRAW_SOUND       - Sound that will play when you draw a card
 # PENALTY_SOUND    - Sound that will play when the revive penalty is applied
 # DECK_ICON        - Icon that displays an actors deck size in battle
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 #                    ["filename", volume, pitch]  -> ["", 0, 0] means no sound
  DRAW_SOUND        = [   "Book1",    100,   150]
  PENALTY_SOUND     = [ "Attack1",    100,    50]
  DECK_ICON         = 228


 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
 #                                   Cards
 #------------------------------------------------------------------------------
 # CUSTOM_CARD_BG   - Name of the windowskin used for cards (in Graphics/System)
 # CARD_BACK_OP     - Background opacity of cards
 # CARD_NAME_UP     - If true, card names will be written in capital letters
 # MP_COLOR         - Textcolor the mana costs are drawn in
 # TP_COLOR         - Textcolor the tp costs are drawn in
 # RARITY           - Name and icon index of the raritys your cards have
 # TYPES            - Different types your cards can have
 # ELEMENT_COLOR    - Background color of your cards based on their element ID
 #-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  CUSTOM_CARD_BG    = "Window_Chrome"   # RPG Maker default is "Window"
  CARD_BACK_OP      = 255
  CARD_NAME_UP      = true
  MP_COLOR          = 4
  TP_COLOR          = 3
  
  RARITY = {
 #      ID => [ icon,     "name"]
         1 => [  127,   "common"],
         2 => [  126, "uncommon"],
         3 => [  125,     "rare"],
  } # do not remove this
  
  TYPE = {
 #      ID => "name"
         1 => "Spell",
         2 => "Support",
         3 => "Buff",
  } # do not remove this
  
  ELEMENT_COLOR = {
 #      ID => [red, grn, blu]
         0 => [150, 150, 150],   # 0 is used for skills without an element
         1 => [ 50,  50,  50],
         2 => [200,   0,   0],
         3 => [200, 200,   0],
         4 => [  0,   0, 200],
  } # do not remove this


#-------------------------------------------------------------------------------
#
#                                 End Options
#
#-------------------------------------------------------------------------------

  end #CG
end #PC27

################################################################################
#                          Start of script                                     #
################################################################################

$imported = {} if $imported.nil?
$imported["PC27: CardGame System"] = true


#===============================================================================
# Load notetags
#===============================================================================

module DataManager
  
  class <<self; alias load_database_pc27_cardgame load_database; end
    
  def self.load_database
    load_database_pc27_cardgame
    load_notetags_pc27_cardgame
  end
  
  def self.load_notetags_pc27_cardgame
    for skill in $data_skills
      next if skill.nil?
      skill.load_notetags_pc27_cardgame_skill
    end
    for item in $data_items
      next if item.nil?
      item.load_notetags_pc27_cardgame_item
    end
  end
  
end


class RPG::UsableItem < RPG::BaseItem
  
  attr_accessor :card_id
  attr_accessor :type
  attr_accessor :rarity
  
  def load_notetags_pc27_cardgame_skill
    @description = wordwrap(@description)
    @card_id = 0
    @type    = 1
    @rarity  = 1
    self.note.split(/[\r\n]+/).each { |line|
      if /<card id: (?<inr>\d+)>/i =~ line
        @card_id = inr.to_i
      elsif /<card type: (?<tnr>\d+)>/i =~ line
        @type = tnr.to_i
      elsif /<card rarity: (?<rnr>\d+)>/i =~ line
        @rarity = rnr.to_i
      end
      }
    end
    
  def load_notetags_pc27_cardgame_item
    @description = wordwrap(@description)
  end
    
  #-----------------------------------------------------------------------------
  # Method to rearange text so it fits inside a window
  #-----------------------------------------------------------------------------
  
  def wordwrap(desc_text, window = nil, default_max_chars = 16)
    max_chars = (window ? (window.width - 2 * window.padding) / 10 : default_max_chars)
    text, line= "", ""
    desc_text.split(/[\r\n ]+/).each { |word|
    if word.size + line.size > max_chars
      text += line+"\n"
      line = word
    else
      line += word
    end
    line += " "
    }
    text += line
    return text
  end
  
end
    
#===============================================================================
# Game_Battler
#===============================================================================
  
class Game_Battler < Game_BattlerBase

  #-----------------------------------------------------------------------------
  # defines card actions for non actors, in case the user messes up
  #-----------------------------------------------------------------------------
  def revive_grave(show = true) ;end
  def revive_penalty            ;end
  def shuffle_deck(sound = true);end
  def card_to_grave?(id)        ;end
  def throw_cards(n)            ;end
  def draw_cards(n)             ;end
  
end
    
#===============================================================================
# Game_Actor
#===============================================================================
  
class Game_Actor < Game_Battler
  
  #-----------------------------------------------------------------------------
  # Attributes
  #-----------------------------------------------------------------------------
  attr_accessor :deck
  attr_accessor :grave
  attr_accessor :hand

  #-----------------------------------------------------------------------------
  # Adds Hand, Deck and Grave to an Actor (alias)
  #-----------------------------------------------------------------------------
  alias pc27_cardgame_gameactor_setup                                      setup
  def setup(actor_id)
    pc27_cardgame_gameactor_setup(actor_id)
    @deck  = []
    @hand  = []
    @grave = []
  end
  
  #-----------------------------------------------------------------------------
  # Draws n cards from the deck
  #-----------------------------------------------------------------------------
  def draw_cards(n, show = true, sound = true)
    n.times do
      if @deck.length == 0
        add_state(1) if PC27::CG::DECK_EMPTY == 0
        return if PC27::CG::DECK_EMPTY == 0
        if @grave.length == 0
          add_state(1) if PC27::CG::DECK_EMPTY == 1
          return
        else
          revive_grave
          revive_penalty if PC27::CG::REVIVE_PENALTY[0] > 0
        end
      end
      RPG::SE.new(*PC27::CG::DRAW_SOUND).play and 30.times { Graphics.update; Input.update } if sound
      skill = @deck.shift
      @hand.push(skill)
      if show
        $game_message.background = 1
        $game_message.position   = 1
        text = @name + " " + PC27::CG::DRAW_MESSAGE + " " + skill.name
        $game_message.add(text)
      end
    end
  end
  
  #-----------------------------------------------------------------------------
  # Puts all cards from your grave back into your deck
  #-----------------------------------------------------------------------------
  def revive_grave(show = true)
    @deck += @grave
    @grave = []
    shuffle_deck(false)
    if show
      $game_message.background = 1
      $game_message.position = 1
      text = @name + PC27::CG::REVIVE_MSG
      $game_message.add(text)
    end
  end
  
  #-----------------------------------------------------------------------------
  # Revive penalty
  #-----------------------------------------------------------------------------
  def revive_penalty
    percent = PC27::CG::REVIVE_PENALTY[0] * 0.01
    case PC27::CG::REVIVE_PENALTY[1]
    when :hp
      @hp  -= @hp  * percent
    when :mhp
      @hp  -= @mhp * percent
    when :mp
      @mp  -= @mp  * percent
    when :mmp
      @mp  -= @mmp * percent
    end
    RPG::SE.new(*PC27::CG::PENALTY_SOUND).play
  end

  #-----------------------------------------------------------------------------
  # Shuffles the deck
  #-----------------------------------------------------------------------------
  def shuffle_deck(sound = true)
    if sound
      5.times do
        RPG::SE.new(PC27::CG::DRAW_SOUND[0], 100, 150).play
        20.times { Graphics.update; Input.update }
        RPG::SE.new(PC27::CG::DRAW_SOUND[0], 100, 100).play
        10.times { Graphics.update; Input.update }
      end
    end
    @deck = @deck.shuffle
  end
  
  #-----------------------------------------------------------------------------
  # Sorts Hand, Deck or Grave
  #-----------------------------------------------------------------------------
  def sort_cards(location)
    case location
    when :deck
      @deck.sort!{|a,b| a.card_id <=> b.card_id}
    when :hand
      @hand.sort!{|a,b| a.card_id <=> b.card_id}
    when :grave
      @grave.sort!{|a,b| a.card_id <=> b.card_id}
    end
  end

  #-----------------------------------------------------------------------------
  # Tries to put a specific card from your hand to your grave
  #-----------------------------------------------------------------------------
  def card_to_grave?(id)
    for i in (0...@hand.length)
      if @hand[i].id == id
        @grave.push(@hand[i])
        @hand.delete_at(i)
        return true
      end
    end
    return false
  end
  
  #-----------------------------------------------------------------------------
  # Puts n random cards from your hand to your grave
  #-----------------------------------------------------------------------------
  def throw_cards(n)
    if n == 0
      @grave += @hand
      @hand = []
      return
    end
    n.times do
      return if @hand.size == 0
      @grave.push(@hand.slice!(rand(@hand.size-1)))
    end
  end
  
  #-----------------------------------------------------------------------------
  # Shuffles Deck and draws cards at the begin of each battle
  #-----------------------------------------------------------------------------
  def on_battle_start
    super()
    shuffle_deck(false)
    draw_cards(PC27::CG::START_CARDS, false, false)
  end
  
  #-----------------------------------------------------------------------------
  # Draws a card at the end of each turn
  #-----------------------------------------------------------------------------
  def on_turn_end
    super()
    draw_cards(1, true, true) if $game_party.in_battle && @hp != 0
  end
  
  #-----------------------------------------------------------------------------
  # Restore deck at the end of battle
  #-----------------------------------------------------------------------------
  def on_battle_end
    @deck += @hand + @grave
    @hand, @grave = [],[]
    super()
  end
  
  #-----------------------------------------------------------------------------
  # Puts a card to the grave after it has been used
  #-----------------------------------------------------------------------------
  def use_item(item)
    super(item)
    if item.is_a?(RPG::Skill)
      $game_actors[actor.id].card_to_grave?(item.id)
    end
  end

end

#===============================================================================
# Game_Party
#===============================================================================

class Game_Party < Game_Unit
  
  #-----------------------------------------------------------------------------
  # Attributes
  #-----------------------------------------------------------------------------
  attr_accessor :coll
    
  #-----------------------------------------------------------------------------
  # Adds a card collection to the party (alias)
  #----------------------------------------------------------------------------- 
  alias pc27_gameparty_initialize                                     initialize
  def initialize
    pc27_gameparty_initialize
    @coll = []
  end
  
  #-----------------------------------------------------------------------------
  # Adds a new card to the collection
  #----------------------------------------------------------------------------- 
  def add_card_to_album(*args)
    for id in args
      @coll.push($data_skills[id])
    end
  end

end

#===============================================================================
# Window_Base
#===============================================================================

class Window_Base < Window
  
  #-----------------------------------------------------------------------------
  # Enables the Base Window to draw cards
  #----------------------------------------------------------------------------- 
  def draw_card_pic(item)
    return unless item
    contents.clear
    id          = item.card_id.to_s
    draw_text_ex(148 - id.size * 10, height - 48, "#" + id)
    make_cost_text(item.mp_cost, item.tp_cost)
    set_background(item.damage ? item.damage.element_id : 0)
    name        = (PC27::CG::CARD_NAME_UP ? item.name.upcase : item.name)
    icon        = "\\I[" + PC27::CG::RARITY[item.rarity][0].to_s + "]"
    type        = PC27::CG::TYPE[item.type]
    name_x      = 0.5 * width - padding - item.name.size * 5
    draw_all_lines
    draw_text_ex(name_x, 9, name)
    draw_text_ex(0,48, type)
    draw_text_ex(0,83, item.description)
    draw_text_ex(0, height - 48, icon)
  end
  
  def draw_horz_line(y)
    line_color       = normal_color
    line_color.alpha = 48
    line_y           = y + line_height / 2 - 1
    contents.fill_rect(0, line_y, self.width, 2, line_color)
  end

  def make_cost_text(mp_cost, tp_cost)
    if mp_cost == 0
      if tp_cost == 0
        cost = "-"
        cost_size = 1
      else
        cost = "\\c[" + PC27::CG::TP_COLOR.to_s + "]" + tp_cost.to_s
        cost_size = tp_cost.to_s.size
      end
    else
      if tp_cost == 0
        cost = "\\c[" + PC27::CG::MP_COLOR.to_s + "]" + mp_cost.to_s
        cost_size = mp_cost.to_s.size
      else
        cost = "\\c[" + PC27::CG::MP_COLOR.to_s + "]"  + mp_cost.to_s + "\\c[0]/" + "\\c[" + PC27::CG::TP_COLOR.to_s + "]" + tp_cost.to_s
        cost_size = 1 + mp_cost.to_s.size + tp_cost.to_s.size
      end
    end
    draw_text_ex(158-cost_size* 10, 48, cost)
  end

  def set_background(element)
    tone.set(*PC27::CG::ELEMENT_COLOR[element])
    self.back_opacity = PC27::CG::CARD_BACK_OP
  end
  
  def draw_all_lines
    draw_horz_line(36)
    draw_horz_line(60)
    draw_horz_line(204)
  end
  
end

#===============================================================================
# Window_Help
#===============================================================================

class Window_Help < Window_Base
  
  #--------------------------------------------------------------------------
  # Adds a second type of help window to display cards
  #--------------------------------------------------------------------------
  def initialize(line_number = 2, type = 0)
    @type = type
    if @type == 0
      super(0, 0, Graphics.width, fitting_height(line_number))
    elsif @type == 1
      super(Graphics.width - 214, 24, 190, 264)
    end
  end
  
  #--------------------------------------------------------------------------
  # Set Item
  #--------------------------------------------------------------------------
  def set_item(item)
    if @type == 0
      set_text(item ? item.description : "")      
    elsif @type == 1
      if item && item.is_a?(RPG::Skill)
        draw_card_pic(item)
        self.windowskin = Cache.system(PC27::CG::CUSTOM_CARD_BG) if PC27::CG::CUSTOM_CARD_BG
      elsif item && item.is_a?(RPG::Item)
        type_1_item(item)
      else
        self.tone.set($game_system.window_tone)
        self.windowskin = Cache.system("Window")
        self.clear
      end
    end
  end

  def type_1_item(item)
    contents.clear
    name_x      = 0.5 * width - padding - item.name.size * 5
    self.tone.set($game_system.window_tone)
    self.windowskin = Cache.system("Window")
    draw_horz_line(36)
    draw_text_ex(name_x, 9, item.name)
    draw_text_ex(0,83, item.description)
  end
  
  def update_tone
    return unless @type == 0
    self.tone.set($game_system.window_tone)
  end
  
end

#===============================================================================
# Window_SkillList
#===============================================================================

class Window_SkillList < Window_Selectable
  
  #--------------------------------------------------------------------------
  # Make skill list from @hand, not from @skills (overwrite)
  #--------------------------------------------------------------------------
  def make_item_list
    @actor.sort_cards(:hand)
    @data = @actor.hand
  end
  
  #--------------------------------------------------------------------------
  # Prevents the costs from beeing drawn (overwrite)
  #--------------------------------------------------------------------------
  def draw_item(index)
    skill = @data[index]
    if skill
      rect = item_rect(index)
      draw_item_name(skill, rect.x, rect.y, enable?(skill))
    end
  end

end

#===============================================================================
# Window_ActorCommand
#===============================================================================

class Window_ActorCommand < Window_Command
   
  #--------------------------------------------------------------------------
  # Add "End Turn" command
  #--------------------------------------------------------------------------
  def add_turn_end_command
    add_command(PC27::CG::END_TURN, :end_turn)
  end
  
  #--------------------------------------------------------------------------
  # Make new command List (overwrite)
  #--------------------------------------------------------------------------
  def make_command_list
    return unless @actor
    add_skill_commands
    add_item_command if PC27::CG::USE_ITEMS
    add_turn_end_command
  end
  
end

#===============================================================================
# Window_BattleStatus
#===============================================================================

class Window_BattleStatus < Window_Selectable
  
  #--------------------------------------------------------------------------
  # Add deck to Draw Item
  #--------------------------------------------------------------------------
  alias pc27_cardgame_wndbttlstat_draw_item                            draw_item
  def draw_item(index)
    pc27_cardgame_wndbttlstat_draw_item(index)
    actor = $game_party.battle_members[index]
    draw_deck_area(deck_area_rect(index), actor)
  end
  
  #--------------------------------------------------------------------------
  # Shrink basic rect
  #--------------------------------------------------------------------------
  def basic_area_rect(index)
    rect = item_rect_for_text(index)
    rect.width -= gauge_area_width + deck_area_width + 10
    rect
  end
  
  #--------------------------------------------------------------------------
  # Get Deck rect
  #--------------------------------------------------------------------------
  def deck_area_rect(index)
    rect = item_rect_for_text(index)
    rect.x += rect.width - gauge_area_width - deck_area_width
    rect.width = deck_area_width
    rect
  end
  
  #--------------------------------------------------------------------------
  # Get Deck Area Width
  #--------------------------------------------------------------------------
  def deck_area_width
    return 48
  end
  
  #--------------------------------------------------------------------------
  # Draw Deck Area
  #--------------------------------------------------------------------------
  def draw_deck_area(rect, actor)
    draw_text(rect.x + 24, rect.y, 24, rect.height, actor.deck.size.to_s)
    draw_icon(PC27::CG::DECK_ICON, rect.x, rect.y)
  end
  
end

#===============================================================================
# Window_BattleSkill
#===============================================================================

class Window_BattleSkill < Window_SkillList
  
  #-----------------------------------------------------------------------------
  # changes the BattleSkillList Window layout
  #-----------------------------------------------------------------------------
  def initialize(help_window, info_viewport)
    y = 0
    super(0, 0, (Graphics.width - 210) * 0.7, info_viewport.rect.y)
    self.visible = false
    @help_window = help_window
    @info_viewport = info_viewport
  end
  
  def col_max
    return 1
  end

end

#===============================================================================
# Window_BattleItem
#===============================================================================

class Window_BattleItem < Window_ItemList
  
  #-----------------------------------------------------------------------------
  # changes the BattleItemList Window layout
  #-----------------------------------------------------------------------------
  def initialize(help_window, info_viewport)
    y = 0
    super(0, 0, (Graphics.width - 210) * 0.7, info_viewport.rect.y)
    self.visible = false
    @help_window = help_window
    @info_viewport = info_viewport
  end
  
  def col_max
    return 1
  end
  
end

#===============================================================================
# Window_CardSelect
#===============================================================================

class Window_CardSelect < Window_SkillList
  
  attr_accessor :actor
  attr_accessor :cards
  attr_accessor :sort_index

  def initialize(help_window, info_viewport)
    super(0, 0, (Graphics.width - 210) * 0.7, info_viewport.rect.y)
    self.visible = false
    @help_window = help_window
    @info_viewport = info_viewport
    @amn, @loc, @des, @typ = 0, :none, :none, :none
    @cards  = []
    @sort_index = -1
  end
  
  def col_max
    return 1
  end
  
  def make_item_list
    @data = @cards
  end

  def enable?(item)
    @actor
  end

  #--------------------------------------------------------------------------
  # * Show Window
  #--------------------------------------------------------------------------
  def show
    select(0)
    @help_window.show
    super
  end
  #--------------------------------------------------------------------------
  # * Hide Window
  #--------------------------------------------------------------------------
  def hide
    @help_window.hide
    super
  end

end

#===============================================================================
# Scene_Battle
#===============================================================================

class Scene_Battle < Scene_Base
  
  #-----------------------------------------------------------------------------
  # Changes Next Command so it performs Actions (overwrite)
  #----------------------------------------------------------------------------- 
  alias pc27_cardgame_scenebattle_next_command                      next_command
  def next_command
    return if @card_select_window.active
    if action?
      perform_action
    else
      pc27_cardgame_scenebattle_next_command
    end
  end
  
  #--------------------------------------------------------------------------
  # Checks if there is an Action to use
  #--------------------------------------------------------------------------
  def action?
    return false if BattleManager.actor.nil?
    return false if BattleManager.actor.input.nil?
    action = BattleManager.actor.input.item
    return !action.nil?
  end
  
  #--------------------------------------------------------------------------
  # Performs Action
  #--------------------------------------------------------------------------
  def perform_action
    hide_instant_action_windows
    @subject = BattleManager.actor
    if @subject.current_action.valid?
      execute_action 
    end
    process_event
    loop do
      @subject.remove_current_action
      break if $game_troop.all_dead?
      break unless @subject.current_action
      @subject.current_action.prepare
      execute_action if @subject.current_action.valid?
    end
    process_action_end
    @subject.make_actions
    @subject = nil
    show_instant_action_windows
  end
  
  #--------------------------------------------------------------------------
  # From Yanflys Instantcast
  #--------------------------------------------------------------------------
  def hide_instant_action_windows
    if $imported["YEA-BattleEngine"]
      @info_viewport.visible = true
      @status_aid_window.hide
      @status_window.show
      @actor_command_window.show
    end
  end
  
  #--------------------------------------------------------------------------
  # Activates actor
  #--------------------------------------------------------------------------
  def show_instant_action_windows
    if $imported["YEA-BattleEngine"]
      @info_viewport.visible = true
    end
    start_actor_command_selection unless @card_select_window.active
    status_redraw_target(BattleManager.actor)
    next_command unless BattleManager.actor.inputable?
  end
  
  #--------------------------------------------------------------------------
  # Redrwas target after action
  #--------------------------------------------------------------------------
  def status_redraw_target(target)
    return unless target.actor?
    @status_window.draw_item($game_party.battle_members.index(target))
  end
  
  #--------------------------------------------------------------------------
  # Add end turn command and remove prior command (overwrite)
  #--------------------------------------------------------------------------
  def create_actor_command_window
    @actor_command_window = Window_ActorCommand.new
    @actor_command_window.viewport = @info_viewport
    @actor_command_window.set_handler(:attack,   method(:command_attack))
    @actor_command_window.set_handler(:skill,    method(:command_skill))
    @actor_command_window.set_handler(:guard,    method(:command_guard))
    @actor_command_window.set_handler(:item,     method(:command_item))
    @actor_command_window.set_handler(:end_turn, method(:command_end_turn))
    @actor_command_window.x = Graphics.width
  end
  
  #--------------------------------------------------------------------------
  # Clears actions and ends the actors turn
  #--------------------------------------------------------------------------
  def command_end_turn
    BattleManager.actor.clear_actions
    next_command
  end
    
  
  #--------------------------------------------------------------------------
  # Prevents messages from closing windows (overwrite)
  #--------------------------------------------------------------------------
  def update_message_open
  end

  #--------------------------------------------------------------------------
  # Shows a different Help Window in Battle (overwrite)
  #--------------------------------------------------------------------------
  def create_help_window
    @help_window = Window_Help.new(2, 1)
    @help_window.visible = false
  end

  #--------------------------------------------------------------------------
  # Creates the window needed to select cards
  #--------------------------------------------------------------------------
  def create_card_select_window
    @card_select_window = Window_CardSelect.new(@help_window, @info_viewport)
    @card_select_window.set_handler(:ok,     method(:select_cards_ok))
    @card_select_window.set_handler(:cancel, method(:select_cards_cancel))
  end
  
  alias pc27_cardgame_scenebattle_create_all_windows          create_all_windows
  def create_all_windows
    pc27_cardgame_scenebattle_create_all_windows
    create_card_select_window
  end

  #--------------------------------------------------------------------------
  # Evaluates card effects (alias)
  #--------------------------------------------------------------------------
  alias pc27_cardgame_scenebattle_use_item                              use_item
  def use_item
    pc27_cardgame_scenebattle_use_item
    eval_card_effect(@subject.current_action.item) if @subject.is_a?(Game_Actor)
  end

  def eval_card_effect(item)
    item.note.split(/[\r\n]+/).each { |line|
    # --- draw cards ---
      if /<draw cards: (?<am>\d+), (?<ch>\d+), (?<trg>....)>/i =~ line
        if trg == "self"
          if rand(100) < ch.to_i
            @subject.draw_cards(am.to_i)
            wait_for_message
          end
        elsif trg == "targ"
          targets = @subject.current_action.make_targets.compact
          for target in targets
            if rand(100) < ch.to_i
              target.draw_cards(am.to_i)
              need_wait = true
            end
          end
          wait_for_message if need_wait
        end
    # --- select cards ---
      elsif /<select cards: (?<amn>\d+), (?<loc>....), (?<des>....), (?<typ>....)>/i =~ line
        text = "Looking at " + @subject.name + "s " + 
        case loc
        when "deck"
          PC27::CG::DECK
        when "hand"
          PC27::CG::HAND
        when "grav"
          PC27::CG::GRAVE
        end
        $game_message.background = 1
        $game_message.position   = 1
        $game_message.add(text)
        wait_for_message
        select_cards(amn.to_i, loc.to_sym, des.to_sym, typ.to_sym)
        #@actor_command_window.deactivate
      end
      }
    end
    
  #--------------------------------------------------------------------------
  # Opens and manages the card select window
  #--------------------------------------------------------------------------
  def select_cards(amn, loc, des, typ)      
    @card_select_window.actor = BattleManager.actor
    case loc
    when :deck
      (amn == 0 ? amn = @card_select_window.actor.deck.size : amn)
      amn.times do
        next if @card_select_window.actor.deck.size == 0
        @card_select_window.cards.push(@card_select_window.actor.deck.shift)
      end
    when :hand
      (amn == 0 ? amn = @card_select_window.actor.hand.size : amn)
      amn.times do
        next if @card_select_window.actor.hand.size == 0
        @card_select_window.cards.push(@card_select_window.actor.hand.shift)
      end
    when :grav
      (amn == 0 ? amn = @card_select_window.actor.grave.size : amn)
      amn.times do
        next if @card_select_window.actor.grave.size == 0
        @card_select_window.cards.push(@card_select_window.actor.grave.shift)
      end
    end
    @card_select = [des, typ]
    @card_select_window.refresh
    @card_select_window.show.activate
  end
  
  def select_cards_ok
    if @card_select[1] == :look
      select_cards_cancel
    elsif @card_select[1] == :sort
      if @card_select_window.sort_index >= 0
        swap_cards(@card_select_window.sort_index, @card_select_window.index)
        @card_select_window.sort_index = -1
        @card_select_window.refresh
      else
        @card_select_window.sort_index = @card_select_window.index
      end
      @card_select_window.activate
    elsif @card_select[1] == :take
      item = @card_select_window.item
      @card_select_window.actor.hand.push(item)
      @card_select_window.cards.delete_at(@card_select_window.cards.index(item))
      select_cards_cancel
    end
  end

  def select_cards_cancel
    @card_select_window.hide.deactivate
    @card_select_window.sort_index = -1
    restore_selected_cards
    start_actor_command_selection
  end

  def restore_selected_cards
    case @card_select[0]
    when :deck
      @card_select_window.cards.reverse.each { |card| 
        @card_select_window.actor.deck.unshift(card)
      }
      @card_select_window.actor.shuffle_deck if @card_select[1] == :take && @card_select_window.actor.deck.size != 0
    when :hand
      @card_select_window.cards.reverse.each { |card| 
        @card_select_window.actor.hand.unshift(card)
      }
    when :grav
      @card_select_window.cards.reverse.each { |card| 
        @card_select_window.actor.grave.unshift(card)
      }
    end
    @card_select_window.cards = []
  end
  
  def swap_cards(index1, index2)
    @card_select_window.cards[index1], @card_select_window.cards[index2] =
    @card_select_window.cards[index2], @card_select_window.cards[index1]
  end
  
end

#===============================================================================
# Scene_Deck
#===============================================================================

class Scene_Deck < Scene_MenuBase
  
  #--------------------------------------------------------------------------
  # Start
  #--------------------------------------------------------------------------
  def start
    super()
    create_filter_window
    create_deck_window
    create_coll_window
    create_text_window
    create_card_window
    create_info_window
  end
  
  #--------------------------------------------------------------------------
  # Creates a window to display deck cards
  #--------------------------------------------------------------------------
  def create_deck_window
    @deck_window = Window_Deck.new(0,64)
    @deck_window.set_handler(:cancel,   method(:return_scene))
    @deck_window.set_handler(:ok,       method(:deck_to_coll))
  end
  
  #--------------------------------------------------------------------------
  # Creates a window to display collection cards
  #--------------------------------------------------------------------------
  def create_coll_window
    @coll_window = Window_Coll.new((Graphics.width - 210)*0.5, 64)
    @coll_window.set_handler(:cancel,   method(:return_scene))
    @coll_window.set_handler(:ok,       method(:coll_to_deck))
    @coll_window.deactivate
  end
  
  #--------------------------------------------------------------------------
  # Creates the window that shows where you are
  #--------------------------------------------------------------------------
  def create_text_window
    @text_window = Window_Base.new(0 ,0, Graphics.width - 210, 64)
    text = $game_party.menu_actor.name + "s " + PC27::CG::DECK
    xpos = [@text_window.width * 0.5 - 10 - @text_window.text_size(text).width * 0.5, 0].max
    @text_window.draw_text_ex(xpos, 8, text)
  end
  
  #--------------------------------------------------------------------------
  # Creates the window that shows the currently selected card
  #--------------------------------------------------------------------------
  def create_card_window
    @card_window = Window_Card.new(Graphics.width - 200, 10, 190, 264)
    @card_window.windowskin = Cache.system(PC27::CG::CUSTOM_CARD_BG) if PC27::CG::CUSTOM_CARD_BG
    @card_window.tone.set(0,0,0,0)
  end
  
  #-----------------------------------------------------------------------------
  # Creates a info window
  #-----------------------------------------------------------------------------
  def create_info_window
    height = Graphics.height - 284
    @count_window = Window_Base.new(
    Graphics.width - 210, Graphics.height - height, 210, height)
    @count_window.draw_text_ex(0,0, PC27::CG::CARD_HELP_WINDOW)
  end
  
  #--------------------------------------------------------------------------
  # Creates a window to filter cards
  #--------------------------------------------------------------------------
  def create_filter_window
    @filter_window = Window_Filter.new(0,Graphics.height * 0.5 - 48)
    @filter_window.set_handler(:cancel,   method(:close_filter))
    @filter_window.set_handler(:ok,       method(:change_filter))
    @filter_window.z = 150
    @filter_window.hide
    @filter_window.deactivate
  end

  #-----------------------------------------------------------------------------
  # Changes between collection and deck window
  #-----------------------------------------------------------------------------    
  def change_to_coll
    @coll_window.activate
    @deck_window.deactivate
    @text_window.contents.clear
    xpos = [@text_window.width * 0.5 - 10 - @text_window.text_size(PC27::CG::COLLECTION).width * 0.5, 0].max
    text = PC27::CG::COLLECTION
    @text_window.draw_text_ex(xpos, 8, text)
    Sound.play_cursor
    Input.update
  end
      
  def change_to_deck
    @deck_window.activate
    @coll_window.deactivate
    @text_window.contents.clear
    text = $game_party.menu_actor.name + "s " + PC27::CG::DECK
    xpos = [@text_window.width * 0.5 - 10 - @text_window.text_size(text).width * 0.5, 0].max
    @text_window.draw_text_ex(xpos, 8, text)
    Sound.play_cursor
    Input.update
  end
  
  #--------------------------------------------------------------------------
  # Adds commands to exchange cards
  #--------------------------------------------------------------------------
  def coll_to_deck
    if $game_party.menu_actor.deck.size >= PC27::CG::MAX_DECK_SIZE
      RPG::SE.new("Buzzer1", 80, 100).play
      return
    end
    /coll(?<skill_id>\d+)/ =~ @coll_window.current_symbol.to_s
    skill_id = skill_id.to_i
    if $game_party.menu_actor.deck.count{ |skill| skill.id == skill_id } >= PC27::CG::MAX_SAME_CARDS
      RPG::SE.new("Buzzer1", 80, 100).play
      return
    end
    for skill in $game_party.coll
      if skill.id == skill_id
        $game_party.menu_actor.deck.push(
        $game_party.coll.slice!($game_party.coll.index(skill)))
        break
      end
    end
    RPG::SE.new("Cursor1", 80, 100).play
    @deck_window.refresh
    @coll_window.refresh
  end
  
  def deck_to_coll
    /deck(?<skill_id>\d+)/ =~ @deck_window.current_symbol.to_s
    skill_id = skill_id.to_i
    for skill in $game_party.menu_actor.deck
      if skill.id == skill_id
        $game_party.coll.push(
        $game_party.menu_actor.deck.slice!($game_party.menu_actor.deck.index(skill)))
        break
      end
    end
    RPG::SE.new("Cursor1", 80, 100).play
    @deck_window.refresh
    @coll_window.refresh
  end
  
  #--------------------------------------------------------------------------
  # Activates filter
  #--------------------------------------------------------------------------
  def activate_filter
    @filter_window.show
    @filter_window.activate
    @deck_window.deactivate
    @coll_window.deactivate
  end
  
  #--------------------------------------------------------------------------
  # Changes filter settings
  #--------------------------------------------------------------------------
  def change_filter
    case @filter_window.current_symbol
    when :filter_element
      @coll_window.filter[0]   += 1
      @filter_window.filter[0] += 1
      @coll_window.filter[0]    = 0 if $data_system.elements.size == @coll_window.filter[0]
      @filter_window.filter[0]  = 0 if $data_system.elements.size == @filter_window.filter[0]
    when :filter_type
      @coll_window.filter[1]   += 1
      @filter_window.filter[1] += 1
      @coll_window.filter[1]    = 0 unless PC27::CG::TYPE.has_key?(@coll_window.filter[1])
      @filter_window.filter[1]  = 0 unless PC27::CG::TYPE.has_key?(@filter_window.filter[1])
    when :filter_rarity
      @coll_window.filter[2]   += 1
      @filter_window.filter[2] += 1
      @coll_window.filter[2]    = 0 unless PC27::CG::RARITY.has_key?(@coll_window.filter[2])
      @filter_window.filter[2]  = 0 unless PC27::CG::RARITY.has_key?(@filter_window.filter[2])
    end
    @filter_window.refresh
    @coll_window.refresh
  end
  
  #--------------------------------------------------------------------------
  # Deativates filter
  #--------------------------------------------------------------------------
  def close_filter
    @filter_window.hide
    @filter_window.deactivate
    @coll_window.activate
    @coll_window.select(0)
  end

  
  #--------------------------------------------------------------------------
  # * Frame Update
  #--------------------------------------------------------------------------
  def update
    super()
  
    #--------------------------------------------------------------------------
    # Changes between collection and deck window
    #--------------------------------------------------------------------------
    change_to_coll  if Input.trigger?(:RIGHT) && @filter_window.visible == false
    change_to_deck  if Input.trigger?(:LEFT)  && @filter_window.visible == false
    activate_filter if Input.trigger?(:X)     && @filter_window.visible == false
  
    #--------------------------------------------------------------------------
    # Redraws card, if neccessary
    #--------------------------------------------------------------------------
    if @coll_window.active
      symbol = @coll_window.current_symbol
    elsif @deck_window.active
      symbol = @deck_window.current_symbol
    end
    
    if symbol != @symbol 
      @symbol = symbol
      if @symbol == :nothing
        @card_window.contents.clear
        @card_window.tone.set(0,0,0,0)
        return
      end
      /[kl](?<id>\d+)/ =~ @symbol.to_s
      @card_window.draw_card_pic($data_skills[id.to_i])
    end
    
  end
  
end


class Window_Deck < Window_Command
  
  #--------------------------------------------------------------------------
  # Makes Command List
  #--------------------------------------------------------------------------
  def make_command_list
    add_deck_commands
  end
  #--------------------------------------------------------------------------
  # Add Card Commands to List
  #--------------------------------------------------------------------------
  def add_deck_commands
    $game_party.menu_actor.sort_cards(:deck)
    deck = $game_party.menu_actor.deck
    if deck.empty?
      add_command("---", :nothing)
      return
    end
    hash = {}
    for skill in deck
      if hash.has_key?(skill.id)
        hash[skill.id] += 1
      else
        hash[skill.id] = 1
      end
    end
    hash.each_key do |id|
     add_command(hash[id].to_s + "x " + $data_skills[id].name, ("deck" + id.to_s).to_sym)
    end
  end
  #--------------------------------------------------------------------------
  # Get Window Height
  #--------------------------------------------------------------------------
  def window_height
    Graphics.height - 64
  end
  #--------------------------------------------------------------------------
  # Get Window width
  #--------------------------------------------------------------------------
  def window_width
    (Graphics.width - 210) * 0.5
  end

  #--------------------------------------------------------------------------
  # Overwrite process_ok so the window won't be disabled
  #--------------------------------------------------------------------------
  def process_ok
    if current_item_enabled?
      Input.update
      call_ok_handler
      select(index - 1) unless current_symbol
    else
      Sound.play_buzzer
    end
  end

end


class Window_Coll < Window_Command
  
  attr_accessor :filter
    
  def initialize(width, heigth)
    @filter = [0,0,0]
    super(width, heigth)
  end

  #--------------------------------------------------------------------------
  # Makes Command List
  #--------------------------------------------------------------------------
  def make_command_list
    add_coll_commands
  end
  
  #--------------------------------------------------------------------------
  # Add Collection Commands to List
  #--------------------------------------------------------------------------
  def add_coll_commands
    $game_party.coll.sort!{|a,b| a.id <=> b.id}
    coll = $game_party.coll
    if coll.empty?
      add_command("---", :nothing)
      return
    end
    hash = {}
    for skill in coll
      next unless match_filter?(skill)
      if hash.has_key?(skill.id)
        hash[skill.id] += 1
      else
        hash[skill.id] = 1
      end
    end
    hash.each_key do |id|
      add_command(hash[id].to_s + "x " + $data_skills[id].name, ("coll" + id.to_s).to_sym)
    end
  end
  
  #--------------------------------------------------------------------------
  # Checks if a card meets the specified filter criteria
  #--------------------------------------------------------------------------
  def match_filter?(skill)
    return false unless skill.damage.element_id  == @filter[0] || @filter[0] == 0
    return false unless skill.type        == @filter[1] || @filter[1] == 0
    return false unless skill.rarity      == @filter[2] || @filter[2] == 0
    return true
  end

  
  #--------------------------------------------------------------------------
  # Get Window Height
  #--------------------------------------------------------------------------
  def window_height
    Graphics.height - 64
  end
  #--------------------------------------------------------------------------
  # Get Window width
  #--------------------------------------------------------------------------
  def window_width
    (Graphics.width - 210) * 0.5
  end

  def process_ok
    if current_item_enabled?
      Input.update
      call_ok_handler
      select(index - 1) unless current_symbol
    else
      Sound.play_buzzer
    end
  end

end


class Window_Filter < Window_Command
  include PC27::CG

  attr_accessor :filter
  
  def initialize(width, heigth)
    @filter = [0,0,0]
    super(width, heigth)
    hide
  end
    
  #--------------------------------------------------------------------------
  # Makes Command List
  #--------------------------------------------------------------------------
  def make_command_list
    add_filter_commands
  end
  
  #--------------------------------------------------------------------------
  # Add Collection Commands to List
  #--------------------------------------------------------------------------
  def add_filter_commands
    add_command(FILTER_TEXT + F_ELEMENT + ( @filter[0]==0 ? "---" : $data_system.elements[@filter[0]] ), :filter_element)
    add_command(FILTER_TEXT + F_TYPE    + (@filter[1]==0 ? "---" : TYPE[@filter[1]]),        :filter_type)
    add_command(FILTER_TEXT + F_RARITY  + (@filter[2]==0 ? "---" : RARITY[@filter[2]][1]),   :filter_rarity)
  end
  
  #--------------------------------------------------------------------------
  # Get Window Height
  #--------------------------------------------------------------------------
  def window_height
    96
  end
  #--------------------------------------------------------------------------
  # Get Window width
  #--------------------------------------------------------------------------
  def window_width
    Graphics.width 
  end
 
  def process_ok
    if current_item_enabled?
      RPG::SE.new("Cursor1", 80, 100)
      Input.update
      call_ok_handler
    else
      Sound.play_buzzer
    end
  end

end


class Window_Card < Window_Base
  
  def update_tone
  end
  
end

class Window_MenuCommand < Window_Command
  
  #--------------------------------------------------------------------------
  # Replaces skills with Deck
  #--------------------------------------------------------------------------

  def add_main_commands
    add_command(Vocab::item,    :item,   main_commands_enabled)
    add_command(PC27::CG::DECK, :deck,   main_commands_enabled)
    add_command(Vocab::equip,   :equip,  main_commands_enabled)
    add_command(Vocab::status,  :status, main_commands_enabled)
  end

end


class Scene_Menu < Scene_MenuBase  

  #--------------------------------------------------------------------------
  # Adds a handler to access the deck scene (alias)
  #--------------------------------------------------------------------------
  alias pc27_cardgame_scenemenu_create_cmd_wdw             create_command_window
  def create_command_window
    pc27_cardgame_scenemenu_create_cmd_wdw
    @command_window.set_handler(:deck,    method(:command_personal))
  end


  #--------------------------------------------------------------------------
  # Adds :deck to the personal command process (alias)
  #--------------------------------------------------------------------------
  alias pc27_cardgame_scenemenu_on_personal_ok                    on_personal_ok
  def on_personal_ok
    pc27_cardgame_scenemenu_on_personal_ok
    case @command_window.current_symbol
    when :deck
      SceneManager.call(Scene_Deck)
    end
  end

end

################################################################################
#                            End of script                                     #
################################################################################

 

 
Compatibility:
This is a battle system, therefore it won't work with other battle systems, like free turn battle, or charged battle.
The script also modifies the battle scene by changing it's help window and adding a new window for special card effects. Any script that messes around with one of these will probably cause an error.
Since I wanted to use this script together with the Yanfly Battle Engine, I am able provide a fix for this one:

 

#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# This script snippet manages compatibility issues between the scripts:
# Yanfly Engine Ace - Ace Battle Engine v1.22
# and
# pencilcase27 - CardGame Skill/Battle System v1.00
#
# Please place it beneath both of them.
#=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

class Scene_Battle < Scene_Base
  def set_help_window
  end
end

class Window_PartyCommand < Window_Command
  def process_handling
    return unless open? && active
    return super
  end
end

class Window_ActorCommand < Window_Command
  def process_handling
    return unless open? && active
    return super
  end
end

class Window_BattleSkill < Window_SkillList
  def col_max
    return 2
  end
end

class Window_BattleItem < Window_ItemList
  def col_max
    return 2
  end
end

class Window_BattleStatus < Window_Selectable
  def draw_deck_area(rect, actor)
    text = actor.deck.size.to_s + "/" + PC27::CG::MAX_DECK_SIZE.to_s
    draw_text(rect.x+2, 2 * line_height, rect.width-4, line_height, text)
  end
  def deck_area_rect(index)
    item_rect(index)
  end
end

 
 
Terms of Use:
Free for not commercial use, as long as credits are given.
Please do not use this script in commercial projects.
 
Thanks:
DiamondandPlatinum3 - without his tutorials this would have not been possible.
Yanfly - looking through his code helped a lot whenever I was lost, especially the Instant Cast script.
And the nice fellas in this community who answerd my questions, especially our code fary who got me interessted in all this mess that consumed the last week of my life... :P
 
Final note:
The main reason I wrote this script was not because I needed a card game script, but because I wanted to learn rgss3 and ruby. This means that this is by far my biggest script so far and if you choose to use it, expect to find the one or other bug. But I ensure you, I am more than eager to fix every single one of them!
Also I found myself enjoying reading through other scripts, seeing how others do this and that. And if any scripter out there feels the same and wants to take a look at my project, I would appreciate any feedback, and even if the only feedback you can give is: "Script is a mess, I don't understand a word, pls re-write!"

 

 

I ASKED FOR THIS LONG AGO!! IM SO HAPPY NOW! Now you need a shop with cards .3.

 

Also, DEMO PLEASE

Share this post


Link to post
Share on other sites

I've been trying to refresh this page several times but the pics never show up..

 

Anyone have the same problem?
I really want to know the pics ;___;

Share this post


Link to post
Share on other sites

The screenshots work for me.

 

Also, very nice looking script/system here.

Share this post


Link to post
Share on other sites

I added an Imgur album with all the pictures, should you be unable to see them here.

 

Card Shops are on the to do list, but only place 3. First I'd like to add a working demo, something I'll start doing right after I finished this post (and got some breakfast). Second I want to add a field to each actor, so they can play permanent cards with some effects. (not passive boni, thats what buffs are for, but something you can activate once per turn or something like that)

 

Thanks for all the positive feedback!

 

Edit: The demo is up now. I noticed an pretty annoying visual bug in the item menu. It's nothing game breaking. But I still need to fix that.

Edited by pencilcase27

Share this post


Link to post
Share on other sites

Would it be possible to add a bit more preciseness to some functions?

 

For instance:

 

  • Adding any singular card from the grave to the hand or deck
  • Searching the deck or graveyard for a specific element of card(Something like 'Draw any FIRE type card from your deck to your Hand')
  • Adding additional cost(Must discard 2 FIRE type cards to use a specific cards effect)
  • EDIT: And just to throw out another idea that came to me: A possibility of card art? Perhaps by hitting a button it would toggle between the text and the card art? Not even sure if that's possible...but it would be cool.

I was just curious if it was possible, or rather something you considered working on in the future. The system itself is amazing, so I had many ideas for it previously unavailable to me. Marvelous job!

Edited by Sissel Cabanela

Share this post


Link to post
Share on other sites
  • Adding any singular card from the grave to the hand or deck
  • Searching the deck or graveyard for a specific element of card(Something like 'Draw any FIRE type card from your deck to your Hand')
  • Adding additional cost(Must discard 2 FIRE type cards to use a specific cards effect)

 

 <card select: 0, grav, grav, take> would let you add a card from your grave to your hand. But the problem is, this would allow to choose the card you just played to trigger this effect.

But this could be solved together with your second idea, something that should be possible to do. Maybe,

For the third one - I think this can be done with yanflys cost manager, and may be another compability fix.

 

*sigh*

I'll add them to the list... ;)

Edited by pencilcase27

Share this post


Link to post
Share on other sites

It does seem like the Cost Manager would be efficient, however I'm not certain of what custom eval I would be using. Is it currently possible or something you'd likely have to add in to function correctly? The way it currently seems it would completely consume the card rather than sending it to the grave.

 

 

EDIT: Also, side note, while I'm bugging the heck outta you- Is it possible to give certain cards individual Max Limits? For instance, a super OP card that you can only have 1 of in a deck?

Edited by Sissel Cabanela

Share this post


Link to post
Share on other sites

Wow! Just tried the demo and I have to say, this is very impressive. I love it! Just a suggestion, if possible?

 

In the deck menu out of battle, is it possible to add some sort of display that shows how many cards out of whatever the max is for each deck?

 

For an example, using the demo's 25 card limit which we only seem to see in battle. While deck building, say there's a little counter somewhere on the screen saying 0/25 cards in deck at the moment, and when you add 1 card, it will display 1/25 cards in deck at the moment. Something like that to notify the player just how many cards they can add if they wish. I see this type of thing in many other card games so it would be nice to see it here too, again, if possible.

 

Other than that, so far again, I am really liking how things work, it's pretty unique for something in an RM game. I might just consider using this, though I may end up bugging you as well for possible bug fixes and other shenanigans ^_^;;.

 

Edit 1: Bug report. It seems if you use the emp card while having it and two other cards in hand, it will discard 2 cards at random like it's supposed to but when you take a look at your now "empty" hand, there are no cards but the EMP card's info display is still there. Not sure if it's intentional or a real bug. Also, is EMP supposed to still be usable even if you don't have two other cards to discard?

 

Edit 2: Am realizing it does this with any card that causes you to have an empty hand. The last card used will still have it's info displayed even if you have no cards left.

Edited by MHRob

Share this post


Link to post
Share on other sites

@MHRob:

Thats a good suggestion. I'll look into it.

For the bug: The script in the op is now v1.01. If you replace the v1.00 script in the demo, it might be that the bug dissapears, since I changed how those windows work.

And I'd love someone to make a game with this script, thats what a script is for after all! You're not bothering me with your requests and ideas

 

Edit: Yes, EMP should be usable at any time. Maybe I'll modify the throw_card(n) method, so it returns how many cards you discard. Then you could make a skill ala: Discard 3 random cards: Deals 100 damage for each card discarded that way.

Edited by pencilcase27

Share this post


Link to post
Share on other sites

Alright, so I've updated the script in the demo.

 

I found another bug that involves the stimulant item that allows you to draw extra cards. Not sure if other cards/effects that draw extra cards does the same thing but, if you happen to use the stimulant item

when you're about to run out of cards, whether you're at 1 or 0 cards left, the characters hp all of a sudden changes, and the characters deck goes back to +2 cards even though the counter showed you had zero cards before using the stimulant. After using the stimulant one more time, you're character dies instead, which I believe that's supposed to happen, just not the semi-revive part with the stimulant. Again, it's possible that other cards that allow you to draw more cards might have a similar behavior.

 

Also, how would you go about reviving a player who ran out of cards? Would they gain their entire deck back if revived? I'm gonna mess around with it some more to see what other possible bugs I may find.

 

Also, while deck building, is there any way to change the character who's deck you're modifying using the Q and W or any other button to change the character? Sort of like how you can change your current character when on the equip screen, instead of having to exit the deck building scene each time, unless that's absolutely necessary in order for it to properly refresh itself or something.

 

One more thing. Can you have any number of characters with a deck of cards go into battle or is it only limited to 3 characters? Only asking because the demo uses 3 characters so I wanted to be sure.

(was able to add in a 4th character with no problem)

 

Thanks again for creating this script and fixing any reported bugs thus far, I really appreciate it.

 

Edit 1: Alright, so I made a revive item just to test it out and it seems that once a player looses all the cards in their deck and die, they can't be revived. The item is used but the character does not revive. I'm guessing it's because even though it's supposed to remove the death state, it has no way to replenish the dead characters deck with cards. How would I go about doing this?

Edited by MHRob

Share this post


Link to post
Share on other sites

For the "Bug", that's intended. You can configure what happens when you are out of cards. Take a look at the options.

Edit: there is actually something wrong - EMPTY_DECK starts counting at 0, not, as the description says, at 1. Will be fixed in the next version.

 

What happens when you revive a player is none of my bussines :) Removig the death state and healing some hp would be a good start, but other than that you can do whatever you want. All card effects can be used for items as well.

 

You should be able to use as many characters as you wish.

 

And the Q/R-one is a good idea, I'll look into it right now.

 

Edit: This would be an example for an revival item:

 

GtfgW09.png

 

Edited by pencilcase27

Share this post


Link to post
Share on other sites

Alright. I've tried the revive fix with your formula from your screenshot but I believe you're aware that while the player is indeed revived, the number of cards is still 0 and when that characters turn comes up again, with his cards still being at 0, he dies again.

 

Also, another suggestion if you don't mind. I understand that the number of cards in your hand can get rather large (I personally don't mind, lol) and it's cool and all, but is it possible for there to be a way to display how many cards are currently in each characters hands?  This can be displayed somewhere in the same window when your looking at the cards in your hands. This will be especially useful for when you have more cards than what the window can show at a time.

 

I indeed do plan on using this script for my game. Heck, I'm thinking of just re-doing my whole project and having this be the main point as far as the battle system is concerned.

Share this post


Link to post
Share on other sites

I don't know about your revival item, but mine shuffles the characters grave back into his deck. If your deck only consist of the 5 cards you are currently holding on your hand, then yes, the actor will die again. But a character dying with his whole 30+ card deck in his hand - that should not happen.

 

I'll upload a new demo tomorow that includes some of the suggestions made here (and a few bug fixes).

Edited by pencilcase27

Share this post


Link to post
Share on other sites

It's odd. I copied the formula just the way I see it in your screenshot, and while the character is being revived, the characters grave isn't shuffled back so the character is revived with zero cards, so on the characters next turn, he'll die again due to not having cards to draw.

 

Anyways, I will definitely look forward to the updated script. Am really loving this system so far. I have more suggestions but eh, I think I've bugged you enough, lol. Thank you for sharing this script with the rest of us. 

Share this post


Link to post
Share on other sites

Update: both script and demo are now using v1.02

 

- few bug fixes

- cards that search a players grave wont show themself anymore.

- you can now view an actors grave any time during his turn.

- it's now possible to make exceptions on how often a certain card can be present in each actors deck

- the card effect <card select> was divided into three different effects, <view cards>, <sord cards> and <take cards>. Take cards can now define what kind of card the player can choose.

- It's now possible to swap actors in the deck building scene via L and R. Also added a counter that counts the actors deck size.

Edited by pencilcase27

Share this post


Link to post
Share on other sites

Nice! I like the changes. Thanks for uploading a new demo as well.

 

Still having the same issue with the reviving the dead actors grave, however, and in your demo it's the exact same issue.

 

Some screenshots:

 

http://imgur.com/h0g9sYM

 

http://imgur.com/WVfaiMz

 

What's happening is that the actor is being revived, but the deck isn't restored. There have been strange oddities with this, as in sometimes, instead of 0 cards, the actor would revive with 6 cards. No clue why, and it is very random. 

 

Edit: I kindly ask for anyone interested in using this script to try out the demo, and if you have free time, test something out for me since the author is unable to reproduce the problem i'm getting even though I get it every single time but he doesn't. It's in the demo, just need someone else to confirm it besides myself.

 

After entering a battle, use eric for this example. Use the stimulant item and proceed to do so until you die (have zero cards in your hand) and then proceed to revive him with the only revive item on there. Does your card count go back up or does it stay 0? You'll die the following turn since you will have zero cards, but that part is normal. What i'm basically trying to do is make it so that when a revive item is used on a dead player, his or her deck is also replenished, I mean what's the point of reviving an actor if his/her deck isn't replenished and just dies the next turn? 

 

I apologize if this appears rash/rude. It is not my intention, but I admit I'm going a little crazy here trying to figure this out. The skill formula for refreshing the deck doesn't appear to work for the item formula, unless i'm doing it wrong.

 

Edit 2: Here's a video. Never used bandicam before and it was recommended for use in rpg maker vx ace video recording so...

 

https://www.youtube.com/watch?v=X2lfzmiaZwc&feature=youtu.be

 

Just wanted the characters themselves to pretty much have the same reaction i'm having. Not meant to be offensive whatsoever, if you are offended, I apologize!

 

Also, I won't bother bringing up this issue anymore. It seems to only affect me for whatever reason. Oh well.

 

Edit 3: Managed to fix it using the right formula! Fix on page 2! If you happen to be suffering from the same problem, anyways. 

Edited by MHRob

Share this post


Link to post
Share on other sites

@MHRob

 

Unfortunately, I too am unable to reproduce this problem. I'm not entirely sure I understand the problem either, so perhaps I am going about it incorrectly?

 

 

@PencilCase

 

Great work! You actually put all the new features in by the next day. Impressive. 

 

Is there a way to added even MORE specificness to the card search? In the way adding a hidden type, like 'Angel' or 'Demon' like a YuGiOh archtype. For instance, 'Draw 1 FIRE Angel card from the Deck to the Hand', or can that be done with just elements and I don't assign 'Angel' and 'Demon' any element colors so they just seem hidden...Also, could you possibly make it so you can choose what card you wish to discard to the graveyard rather than it being random?

Share this post


Link to post
Share on other sites

@Sissel: That's what types and raritys are for. Remember, just because I called them "type" and "rarity" doesnt mean you have to. You can use them however you want. Since I think two additional card attributes are enough, I think I'll leave it that way. And if your question was if it's possible to only select rare fire spells, or common ice items, thats already possible.

 

And for your second question: I plan on expanding the <take cards> feature, so it specifies not only what cards you can select, but also how many, and where to put them. This would allow for cards like: "search your deck for a card and put it into your grave" or "select two cards from your hand and discard the rest".

However, all those effevts are calculated after the damaging process is done. This means that cards like: "choose and discard X cards: deals X * 100 damage" won't be possible.

Share this post


Link to post
Share on other sites

Oh, you're absolutely right. I can easily change Rarity to specify and archetype and even give it a specific symbol! Thank you very much.

 

Also the second part sounds very much like what I'd want. I merely wanted the 'cost' to use a card be 'discard a card', but would rather the user be able to select which card rather than accidently discarding a powerful card.

Share this post


Link to post
Share on other sites

Two Problems to report now that I decided to move onto finding other issues/bugs/whatever.

 

Problem 1: Game Crashes upon checking out your grave while in a battle.

 

How To Produce this problem: Simply check your grave out and try and select nothing. 

 

Screenshot of said problem: http://i.imgur.com/mIrpEmX.jpg

 

---

 

Problem 2: Entire Party defeated with no effort by the enemy.

 

How To Produce this problem: Simply enter any battle without any cards in your deck.

 

Video of said problem: https://www.youtube.com/watch?v=bYH64ZXF89U&feature=youtu.be

 

----

 

Bandicam seems to have a heart attack whenever I try to record a video with a game crashing error so I am unable to record it, but the screenshot and explanation on how to reproduce the error should suffice as far as the first problem is concerned...

 

As for the second problem. Sure, the person using this system could make it so that they can event it and make it so that the players can't engage in a battle without cards in their deck, but this really should be something handled by the script somehow. Although I don't mind having to event it, a more efficient way is always a good thing, though as far as this card skill system is concerned, how would you even event something like that?

 

Anyways, will edit/post if I find anything else. Please don't get me wrong. I am simply doing this in hopes the author will find ways to fix this script to make it even better. 

Edited by MHRob

Share this post


Link to post
Share on other sites

Thanks for the first one, but I really don't see what's the problem with the second. What should happen if the party enters battle without cards? I cannot prevent battles, since this would break forced battles like random encounter. Also, if anyone enters a battle without cards, then either the player or the developer failed^^

 

Btw, do you understand now how the golden cross item works and why it's not a bug? I read your post here describing what happend and this is 100% intended. If you're still having trouble understanding whats going on, I suggest you read the scripts instructions once more, the part about the skill/item damage formula box to be precise.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×