Envision, Create, Share

Welcome to HBGames, a leading amateur game development forum and Discord server. All are welcome, and amongst our ranks you will find experts in their field from all aspects of video game design and development.

Vancian spellcasting, 1.0 release

Vancian SpellcastingVersion: 1.0
By: Pidey

Introduction

This is a system designed to place a special restriction on spellcasters, while at the same time drastically changing the MP system. This system causes the player to have to decide beforehand what spells he wants. Giving the spellcaster a restriction will allow you to give the spellcaster more interesting spells without making him outshine the other party members. The script also increases damage if one specific spell is set to be used alot.

Features
  • Forces players to decide what spells they want to cast beforehand.
  • Ability to mark some characters as vancian (spellcasters probably), while leaving fighters and such untouched.
  • Allows a character to "specialize" in a specific spell for increased effect.
  • Ability to mark a setup as default, so the player doesn't need to go to the menu every time they visit an inn.
  • *NEW in v1.0* Allows for passive spells, which can turn a mage into a frontline fighter on a semi-permanent basis.
  • *NEW in v1.0* De-clutters the skill menu, removes spells which have not been prepared. This way you can have a HUGE repertoire of spells available to prepare, without cluttering up the skill menu.

Screenshots

Aside from the preparation menu, not much can be shown through a screenshot. That said, here is the screenshot.


Demo

Vancian 1.0 demo

Script

Code:
#==============================================================================

# ** Window_Vancian

#------------------------------------------------------------------------------

#  This window displays usable skills on the Vancian preparation menu

#Vancian version 1.0

# Written by Pidey

#==============================================================================

 

class Window_Vancian < Window_Selectable

  #--------------------------------------------------------------------------

  # * Object Initialization

  #     actor : actor

  #--------------------------------------------------------------------------

  def initialize(actor)

    super(0, 128, 640, 352)

    @actor = actor

    @column_max = 2

    refresh

    self.index = 0

  end

  #--------------------------------------------------------------------------

  # * Acquiring Skill

  #--------------------------------------------------------------------------

  def skill

    return @data[self.index]

  end

  

  def showIndex

    return self.index

  end

  #--------------------------------------------------------------------------

  # * Refresh

  #--------------------------------------------------------------------------

  def refresh

    if self.contents != nil

      self.contents.dispose

      self.contents = nil

    end

    @data = []

    for i in [email=0...@actor.skills.size]0...@actor.skills.size[/email]

      skill = $data_skills[@actor.skills[i]]

      if skill != nil

        @data.push(skill)

      end

    end

    # If item count is not 0, make a bit map and draw all items

    @item_max = @data.size

    if @item_max > 0

      self.contents = Bitmap.new(width - 32, row_max * 32)

      self.contents.font.name = $fontface

      self.contents.font.size = $fontsize

      for i in 0...@item_max

        draw_item(i)

      end

    end

  end

  #--------------------------------------------------------------------------

  # * Draw Item

  #     index : item number

  #--------------------------------------------------------------------------

  def draw_item(index)

    skill = @data[index]

    if @actor.skill_has_sp?(skill.id)

      self.contents.font.color = normal_color

    else

      self.contents.font.color = disabled_color

    end

    x = 4 + index % 2 * 320

    y = index / 2 * 32

    rect = Rect.new(x, y, self.width / @column_max - 32, 32)

    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))

    bitmap = RPG::Cache.icon(skill.icon_name)

    opacity = self.contents.font.color == normal_color ? 255 : 128

    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)

    self.contents.draw_text(x + 28, y, 180, 32, skill.name, 0)

    self.contents.draw_text(x + 190, y, 32, 32, skill.sp_cost.to_s, 2)

    self.contents.draw_text(x + 226, y, 32, 32, @actor.vancian[skill.id].to_s, 2) #this displays how many times the spell is prepared.

  end

  #--------------------------------------------------------------------------

  # * Help Text Update

  #--------------------------------------------------------------------------

  def update_help

    @help_window.set_text(self.skill == nil ? "" : self.skill.description)

  end

end
Code:
#==============================================================================

# ** Window_Vancian_aid

#------------------------------------------------------------------------------

#  This window gives options during the vancian preparation.

#Vancian version 1.0

# Written by Pidey

#==============================================================================

 

class Window_Vancian_aid < Window_Selectable

  #--------------------------------------------------------------------------

  # * Object Initialization

  #--------------------------------------------------------------------------

  def initialize

    super(0, 0, 336, 480)

    self.contents = Bitmap.new(width - 32, height - 32)

    self.contents.font.name = $fontface

    self.contents.font.size = $fontsize

    self.z += 10

    @item_max = 4

    refresh

  end

  #--------------------------------------------------------------------------

  # * Refresh

  #--------------------------------------------------------------------------

  def refresh

    self.contents.clear

    for i in 0...$game_party.actors.size

      x = 4

      y = i * 116

 

      self.contents.draw_text(4, 0, 324, 68, "Set as Default")

      self.contents.draw_text(4, 116, 224, 48, "Clear one of spell")

      self.contents.draw_text(4, 232, 224, 48, "Clear all of spell")

      self.contents.draw_text(4, 348, 224, 48,  "Clear all memory")

      actor = $game_party.actors[i]

    end

  end

  #--------------------------------------------------------------------------

  # * Cursor Rectangle Update

  #--------------------------------------------------------------------------

  def update_cursor_rect

    # Cursor position -1 = all choices, -2 or lower = independent choice

    # (meaning the user's own choice)

    if @index <= -2

      self.cursor_rect.set(0, (@index + 10) * 116, self.width - 32, 96)

    elsif @index == -1

      self.cursor_rect.set(0, 0, self.width - 32, @item_max * 116 - 20)

    else

      self.cursor_rect.set(0, @index * 116, self.width - 32, 96)

    end

  end

end
Code:
#==============================================================================

# ** Window_Skill

#------------------------------------------------------------------------------

#  This window displays usable skills on the skill and battle screens.

#==============================================================================

 

class Window_Skill < Window_Selectable

  #--------------------------------------------------------------------------

  # * Object Initialization

  #     actor : actor

  #--------------------------------------------------------------------------

  alias initialize_old initialize

  def initialize(actor)

    super(0, 128, 640, 352)

    @actor = actor

    @column_max = 2

    refresh

    self.index = 0

    # 戦闘中の場合はウィンドウを画面中央へ移動し、半透明にする

    if $game_temp.in_battle

      self.y = 64

      self.height = 256

      self.back_opacity = 160

    end

  end

  #--------------------------------------------------------------------------

  # * Acquiring Skill

  #--------------------------------------------------------------------------

  alias skill_old skill

  def skill

    if @is_empty == true

      return $data_skills[11] #note:  Replace the 11 with the skill who's description you want shown when memory is empty.

    end

    return @data[@crosspointer[self.index]]

  end

  #--------------------------------------------------------------------------

  # * Refresh

  #--------------------------------------------------------------------------

  alias refresh_old refresh

  def refresh

    if self.contents != nil

      self.contents.dispose

      self.contents = nil

    end

    @data = []

    @crosspointer = [5]

    for i in [email=0...@actor.skills.size]0...@actor.skills.size[/email]

      skill = $data_skills[@actor.skills[i]]

      if skill != nil

        @data.push(skill)

      end

    end

    @item_max = @data.size

    if @item_max > 0

      self.contents = Bitmap.new(width - 32, row_max * 32)

      self.contents.font.name = $fontface

      self.contents.font.size = $fontsize

      @is_empty = true

      if @actor.is_vancian == true

        counter = 0

        for i in [email=0...@data.size]0...@data.size[/email]

          if @actor.vancian[@data[i].id] > 0 #if has spell prepared

            draw_item(i,counter)

            @crosspointer[counter]=i

            counter +=1

          end

        end

        @item_max = counter

      else

        for i in 0...@item_max

          draw_item(i,i)

          @crosspointer[i]=i

        end

      end

    end

  end

  #--------------------------------------------------------------------------

  # * Draw Item

  #     index : item number

  #--------------------------------------------------------------------------

  alias draw_item_old draw_item

  def draw_item(index,loc)

    @is_empty = false

    skill = @data[index]

    if @actor.skill_can_use?(skill.id)

      self.contents.font.color = normal_color

    else

      self.contents.font.color = disabled_color

    end

    x = 4 + loc % 2 * (320)

    y = loc / 2 * 32

    rect = Rect.new(x, y, self.width / @column_max - 32, 32)

    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))

    bitmap = RPG::Cache.icon(skill.icon_name)

    opacity = self.contents.font.color == normal_color ? 255 : 128

    self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 5000), opacity)

    self.contents.draw_text(x + 28, y, 204, 32, skill.name, 0)

    if @actor.is_vancian == true

      self.contents.draw_text(x + 226, y, 32, 32, @actor.vancian[skill.id].to_s, 2)

    else

      self.contents.draw_text(x + 232, y, 48, 32, skill.sp_cost.to_s, 2)

    end

  end

end

 
Code:
#-----------------------------------------------------------------

#Vancian

#-----------------------------------------------------------------

#This class is used to hold a character's Vancian Memory,

#As well as several important functions to the Vancian's working.

#Vancian version 1.0

# Written by Pidey

 

 

class Vancian

  #this class holds a character's vancian memory.

  

  def initialize(master)

    @actor = master

    @current_memory = []

    @prefered_memory = []

    incriment = 1

    while $data_skills[incriment] != nil  #this fills the memory with zeroes, so there aren't any nil

      @prefered_memory[incriment] = 0

      @current_memory[incriment] = 0

      incriment += 1

    end

  end

  

  def ensure_prefered_capacity  #use this to catch errors in the event of maximum SP lowering.

    if prefered_memory_cost <=  $game_actors[@char].max_sp

      return true

    else

      return false

    end

  end

  

  

  def set_as_default #this copies the current memory into prefered memory for later retrieval.

    incriment = 1

    while $data_skills[incriment] != nil

      @prefered_memory[incriment] = @current_memory[incriment]

      incriment += 1

    end

  end

    

  

  def prefered_memory_cost #this returns the total SP cost of prefered spells

    incriment = 1

    total = 0

    while $data_skills[incriment] != nil

      total += $data_skills[incriment].sp_cost * @prefered_memory[incriment]

      incriment += 1

    end

    return total

  end

  

  def current_total  #this returns the total SP cost of all currently memorized spells

    incriment = 1

    total = 0

    while $data_skills[incriment] != nil

      total += $data_skills[incriment].sp_cost * @current_memory[incriment]

      incriment += 1

    end

    return total

  end

  

  

  def set_prefered  #sets memory as prefered, and returns total cost

    incriment = 1

    total = 0

    while $data_skills[incriment] != nil

      self[incriment] = @prefered_memory[incriment]

      total+= $data_skills[incriment].sp_cost * @current_memory[incriment]

      incriment +=1

    end

    return total

  end

  

  def [](line_number)

      return @current_memory[line_number]

  end

    

  def []=(switch_id, value)

    if switch_id <= 5000

      give_special_effect(switch_id, value-@current_memory[switch_id])

      @current_memory[switch_id] = value

    end

  end

  

  

  def give_special_effect(id, times)

    # Note: Here you can cause preparing a spell to change the caster's stats.

    # Simply add a case for the skill's ID, then manipulate the actor's stats appropriately.

    case id 

    #when 14

    # @actor.dex += times   

    end

  end

  

  

  def clear_memory  #warning!  Clears memory WITHOUT restoring maxMP.

    incriment = 1

    while $data_skills[incriment] != nil

      self[incriment] = 0

      incriment += 1

    end

  end

end

 
Code:
#==============================================================================

# ** Scene_Vancian

#------------------------------------------------------------------------------

#  This Class is the Vancian preparation screen

#Vancian version 1.0

# Written by Pidey

#==============================================================================

 

class Scene_Vancian

  

  def initialize(char)

    @char = char

    if not $game_party.actors[@char].is_vancian

      $scene = Scene_Menu.new(1)

      return

    else

      @memory = $game_party.actors[@char].vancian

    end

  end

 

  def main

    @actor = $game_party.actors[@char]

    @help_window = Window_Help.new

    @status_window = Window_SkillStatus.new(@actor)

    @vancian_window = Window_Vancian.new(@actor)

    @vancian_window.help_window = @help_window

    @aid_window = Window_Vancian_aid.new

    @aid_window.visible = false

    Graphics.transition

    loop do

      Graphics.update

      Input.update

      update

      if $scene != self

        break

      end

    end

    Graphics.freeze

    @help_window.dispose

    @status_window.dispose

    @vancian_window.dispose

  end

 

  

  def update

    # Update windows

    @help_window.update

    @status_window.update

    @vancian_window.update

    # If skill window is active: call update_skill

    if @vancian_window.active

      update_vancian

      return

    end

    # If skill target is active: call update_target

    if @aid_window.active

      update_aid

      return

    end

  end

  

  

  def update_vancian

    

    # Pressing B returns to menu

    if Input.trigger?(Input::B)

      $game_system.se_play($data_system.cancel_se)

      $scene = Scene_Menu.new(1)

      return

    end

    

    if Input.trigger?(Input::A)

      $game_system.se_play($data_system.cursor_se)

      @vancian_window.active = false

      temp = @vancian_window.index

      @aid_window.x = (temp +1) % 2 * 304

      @aid_window.visible = true

      @aid_window.active = true

      @aid_window.index = 0

    end

    

    # If C button was pressed

    if Input.trigger?(Input::C)

      # Get currently selected data on the skill window

      @skill = @vancian_window.skill

      # If unable to use

      if @skill == nil or  @actor.sp <@skill.sp_cost

        # Play buzzer SE

        $game_system.se_play($data_system.buzzer_se)

        return

      end

      # Play decision SE

      $game_system.se_play($data_system.decision_se)

      @memory[@skill.id] +=1

      @actor.sp -= @skill.sp_cost  #Preparing a vancian spell lowers SP

      @actor.maxsp -= @skill.sp_cost #maximum SP is also consumed, but returned upon casting

      @vancian_window.refresh

      @status_window.refresh

      return

    end

  end

  

  

  def update_aid

    @aid_window.update

    if Input.trigger?(Input::B)

      $game_system.se_play($data_system.cancel_se)

      @vancian_window.active = true

      @aid_window.visible = false

      @aid_window.active = false

      return

    end

    if Input.trigger?(Input::C)

      case @aid_window.index

      when 0 #set as default

        @actor.vancian.set_as_default

        $game_system.se_play($data_system.decision_se)

      when 1 #clear one of spell

        if @actor.vancian[@vancian_window.skill.id] > 0

          @actor.vancian[@vancian_window.skill.id] -=1

          @actor.maxsp += @vancian_window.skill.sp_cost

          @actor.sp += @vancian_window.skill.sp_cost / 4

          $game_system.se_play($data_system.decision_se)

        else

          $game_system.se_play($data_system.cancel_se)

        end

      when 2 #clear all of one spell

        if @actor.vancian[@vancian_window.skill.id] > 0

          total = @vancian_window.skill.sp_cost * @actor.vancian[@vancian_window.skill.id]

          @actor.maxsp += total

          @actor.sp += total / 3

          $game_system.se_play($data_system.decision_se)

          @actor.vancian[@vancian_window.skill.id] = 0

        else

          $game_system.se_play($data_system.cancel_se)

        end

      when 3 #clear all memory

        total = @actor.vancian.current_total

        @actor.maxsp += total

        @actor.sp = @actor.sp +  total /2

        @actor.vancian.clear_memory

        $game_system.se_play($data_system.decision_se)

      end

      @vancian_window.refresh

      @status_window.refresh

    end

  end

  

end
Code:
# This contains misc things needed for vancian spellcasting.

#Vancian version 1.0

# Written by Pidey

 

 

 

class Game_Actor < Game_Battler

  alias old_setup setup

  def setup(actor_id)

    @vancian = Vancian.new(self)

    if actor_id == 7 or actor_id == 8  #Note: Specify who is vancian here!

      @is_vancian = true

    else

      @is_vancian = false

    end

    old_setup(actor_id)

  end

end

 

 

 

class Game_Battler

  attr_reader   :is_vancian

  attr_reader   :vancian

  alias recover_all_old recover_all

  def recover_all

    if is_vancian == true

      @maxsp_plus += vancian.current_total

      @maxsp_plus = [[@maxsp_plus, -9999].max, 9999].min

      vancian.clear_memory

    end

    @hp = maxhp

    @sp = maxsp

    if is_vancian == true

      if vancian.prefered_memory_cost <= maxsp

        t = vancian.set_prefered

        @maxsp_plus -= t

        @maxsp_plus = [[@maxsp_plus, -9999].max, 9999].min

        @sp -= t

      end

    end

    for i in @states.clone

      remove_state(i)

    end

  end

  

  alias skill_can_use_old? skill_can_use?

  def skill_can_use?(skill_id)

    # If there's not enough SP, or preparation the skill cannot be used.

    if self.is_vancian == true

      if self.vancian[skill_id] == 0

        return false

      end

    else

      if $data_skills[skill_id].sp_cost > self.sp

        return false

      end

    end

    # Unusable if incapacitated

    if dead?

      return false

    end

    # If silent, only physical skills can be used

    if $data_skills[skill_id].atk_f == 0 and self.restriction == 1

      return false

    end

    # Get usable time

    occasion = $data_skills[skill_id].occasion

    # If in battle

    if $game_temp.in_battle

      # Usable with [Normal] and [Only Battle]

      return (occasion == 0 or occasion == 1)

    # If not in battle

    else

      # Usable with [Normal] and [Only Menu]

      return (occasion == 0 or occasion == 2)

    end

  end

  

  def skill_has_sp?(skill_id)

    if $data_skills[skill_id].sp_cost > self.sp

      return false

    end

    return true

  end

  

  alias skill_effect_old skill_effect

  def skill_effect(user, skill)

    self.critical = false

    if ((skill.scope == 3 or skill.scope == 4) and self.hp == 0) or

       ((skill.scope == 5 or skill.scope == 6) and self.hp >= 1)

      return false

    end

    effective = false

    effective |= skill.common_event_id > 0

    hit = skill.hit

    if skill.atk_f > 0

      hit *= user.hit / 100

    end

    hit_result = (rand(100) < hit)

    effective |= hit < 100

    if hit_result == true

      power = skill.power + user.atk * skill.atk_f / 100

      if power > 0

        power -= self.pdef * skill.pdef_f / 200

        power -= self.mdef * skill.mdef_f / 200

        power = [power, 0].max

      end

      rate = 20

      rate += (user.str * skill.str_f / 100)

      rate += (user.dex * skill.dex_f / 100)

      rate += (user.agi * skill.agi_f / 100)

      rate += (user.int * skill.int_f / 100)

      if user.is_vancian == true #Increases the power of a spell for preparing it repeatedly.

        vancian_boost = user.vancian[skill.id] * 0.05 +1

        vancian_boost = vancian_boost ** 1.15

      else

        vancian_boost = 1

      end

      self.damage = (power * rate / 20) * vancian_boost 

      self.damage *= elements_correct(skill.element_set)

      self.damage /= 100

      if self.damage > 0

        if self.guarding?

          self.damage /= 2

        end

      end

      self.damage = self.damage.round

      if skill.variance > 0 and self.damage.abs > 0

        amp = [self.damage.abs * skill.variance / 100, 1].max

        self.damage += rand(amp+1) + rand(amp+1) - amp

      end

      eva = 8 * self.agi / user.dex + self.eva

      hit = self.damage < 0 ? 100 : 100 - eva * skill.eva_f / 100

      hit = self.cant_evade? ? 100 : hit

      hit_result = (rand(100) < hit)

      effective |= hit < 100

    end

    if hit_result == true

      if skill.power != 0 and skill.atk_f > 0

        remove_states_shock

        effective = true

      end

      last_hp = self.hp

      self.hp -= self.damage

      effective |= self.hp != last_hp

      @state_changed = false

      effective |= states_plus(skill.plus_state_set)

      effective |= states_minus(skill.minus_state_set)

      if skill.power == 0

        self.damage = ""

        unless @state_changed

          self.damage = "Miss"

        end

      end

    else

      self.damage = "Miss"

    end

    unless $game_temp.in_battle

      self.damage = nil

    end

    return effective

  end

end

 

class Window_Skill < Window_Selectable

  alias draw_item_old draw_item

  def draw_item(index)

    skill = @data[index]

    if @actor.skill_can_use?(skill.id)

      self.contents.font.color = normal_color

    else

      self.contents.font.color = disabled_color

    end

    x = 4 + index % 2 * (288 + 32)

    y = index / 2 * 32

    rect = Rect.new(x, y, self.width / @column_max - 32, 32)

    self.contents.fill_rect(rect, Color.new(0, 0, 0, 0))

    bitmap = RPG::Cache.icon(skill.icon_name)

    opacity = self.contents.font.color == normal_color ? 255 : 128

    if @actor.is_vancian == true

      self.contents.draw_text(x + 28, y, 180, 32, skill.name, 0)

      self.contents.draw_text(x + 190, y, 32, 32, skill.sp_cost.to_s, 2)

      self.contents.draw_text(x + 226, y, 32, 32, @actor.vancian[skill.id].to_s, 2)

    else

      self.contents.blt(x, y + 4, bitmap, Rect.new(0, 0, 24, 24), opacity)

      self.contents.draw_text(x + 28, y, 204, 32, skill.name, 0)

      self.contents.draw_text(x + 232, y, 48, 32, skill.sp_cost.to_s, 2)

    end

  end

end

 

 

class Scene_Battle

  alias make_skill_action_result_old make_skill_action_result

  def make_skill_action_result

    @skill = $data_skills[@active_battler.current_action.skill_id]

    unless @active_battler.current_action.forcing

      unless @active_battler.skill_can_use?(@skill.id)

        $game_temp.forcing_battler = nil

        @phase4_step = 1

        return

      end

    end

    if @active_battler.is_vancian == true

      @active_battler.vancian[@skill.id] -= 1

      @active_battler.maxsp += @skill.sp_cost

    else

      @active_battler.sp-= @skill.sp_cost

    end

    @status_window.refresh

    @help_window.set_text(@skill.name, 1)

    @animation1_id = @skill.animation1_id

    @animation2_id = @skill.animation2_id

    @common_event_id = @skill.common_event_id

    set_target_battlers(@skill.scope)

    for target in @target_battlers

      target.skill_effect(@active_battler, @skill)

    end

  end

end


Instructions

The Vancian preparation can be called simply by the line $scene = Scene_Vancian.new(<character's location in party>)
You will need to edit your menu yourself to add this. It is also possible to NOT add it to the menu, and instead call it at a different time, such as at inns. If you need help editing your menu system, simply ask, and I can change it for you.

in Vancian_skill_window line 31, change the 11 to the ID of a skill which has a description you want to show when the character's memory is empty.
In Vancian, line 87, is a method where you can set certain skills to have passive effects, simply by being prepared. Simply add another when to the case statement, and change it appropriately.
In Vancian_Misc, line 11, is where you choose which characters are vancian.

Simply place all of the scripts above main to install.


Compatibility

This script is non SDK compliant, and alters the Skill window, and the skill usage method of the battlesystem. It is incompatible with many custom battlesystems, though this should be easy to rectify for a skilled scripter.


Author's Notes

Version 1.0 has several optimizations from last time, as well as a crash fix. It also de-clutters the skill window, allowing massive libraries of spells which can be prepared without bogging down combat.
I have no plans to port the code to VX, as I do not own VX.

Terms and Conditions

May be re-posted and edited at your leisure. Modified versions of the code must be clearly indicated that they are modified and not my original work. If you intend to use this script, please E-mail me at lordpidey@yahoo.com with the name of the game it is being used in.

If this is used in a commercial game, a free copy of the game must be made available to me.
 
This sounds like it could be cool but MegaUpload isn't cooperating, it keeps telling me to type in the 4 digits displayed to download file then I'll type in the correct code, then it gives me the link to click then I click it and... it makes me enter the stupid 4 digit code again XD

Perhaps if you change the host to something, perhaps mediafire, you'll be able to get some comments on this because I doubt anybody is able to download your demo.
 

Thank you for viewing

HBGames is a leading amateur video game development forum and Discord server open to all ability levels. Feel free to have a nosey around!

Discord

Join our growing and active Discord server to discuss all aspects of game making in a relaxed environment. Join Us

Content

  • Our Games
  • Games in Development
  • Emoji by Twemoji.
    Top