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.

User customizable AI script

Pidey's User customizable AI
Version: Alpha3

Introduction

This script not only provides an AI for one character, it also provides a way of modifying the AI while in game. This is done by inserting items that represent snippets of code into the "AI window"


Features
  • Very customizable by the user
  • Ability to customize limited by items, thus the game designer can gradually unlock this complex feature
  • Easy to add new potential lines

Screenshots

http://i12.photobucket.com/albums/a231/pidey/aidemopic.png


Script

Code:
class GratheAI

  

  def main

    $game_variables[74]=1

    if $game_variables[74] == 100

      throw_error

    end

    while $game_variables[71] >= 105 && $game_variables[74] <= 100

      execute_line

    end

    if $game_variables[71] == 0

      $game_variables[75]+=1

      $game_variables[74]=1

    end

    $game_variables[71]=500 #done so that the while statement isn't improperly tripped next time

  end

  

  

  def execute_line

    $game_variables[71] = $grathe_code[$game_variables[75]]    #Stores the contents of the current line

    $game_variables[72] = $grathe_code2[$game_variables[75]]  #Stores the location the line redirects to.

    if $game_variables[71] >= 105 # this means its redirect statement

      change_statement

    else

      chose_action

      $game_variables[75]+=1

    end

    $game_variables[74]+=1

  end

  

  

  

  def chose_action

    case $game_variables[71] #checks contents of current line

    #Note7

    when 83 #attack random

      action_passer(0, 0, -1)

    when 84 #Attack last

      action_passer(0, 0, -1)

    when 85 #defend

      action_passer(0,1,-1)

    when 86 #bullet rain

      if $game_actors[6].sp>=50

        $game_actors[6].sp -= 50

        action_passer(1,100,-1)

      else

        throw_error

      end

    when 87 #recharge

      $game_actors[6].sp += 35

      action_passer(1,101,-1)

    when 88 #Concentrate Fire

      if $game_actors[6].sp>=50

        $game_actors[6].sp -= 50

        action_passer(1,102,-1)

      else

        throw_error

      end

    when 89 #double burst

      if $game_actors[6].sp>=35

        $game_actors[6].sp -= 35

        action_passer(1,105,-1)

      else

        throw_error

      end

    when 90 #heal self

      if $game_actors[6].sp>=5

        $game_actors[6].sp -= 5

        action_passer(1,106,-1)

      else

        throw_error

      end

    end

  end

  

  

  def throw_error

    action_passer(1,83,-1)   #Note8

  end

    

  

  

  def change_statement

    goto = false

    case $game_variables[71] #checks contents of current line

    

    

    #Note 9

    when 105 #a goto statement

      goto = true

    when 106 #SelfHP%>=25

     # p (($game_actors[6].maxhp / 4) <= $game_actors[6].hp).to_s

      goto = ($game_actors[6].maxhp / 4) <= $game_actors[6].hp

    when 107 #selfMP>=50

      goto = $game_actors[6].sp >= 50

    when 108 #selfMP>=10

      goto = $game_actors[6].sp >= 10

    when 109 #random redirect

      $game_variables[72] = rand(7).round

      goto = true

    when 110 #50% chance of redirect

      goto =  rand(2) == 1

    when 111#10% chance of redirect

      goto = rand(10)>=9

    #Add additional Redirect statements here

    end

    if goto

      $game_variables[75] = $game_variables[72]

    else

      $game_variables[75]+=1

    end

  end

 

 

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

  # * Force Action

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

  def action_passer(action_type, action_id, target)

    # Ignore if not in battle

    unless $game_temp.in_battle

      return true

    end

    # Ignore if number of turns = 0

    if $game_temp.battle_turn == 0

      return true

    end

    # Process with iterator (For convenience, this process won't be repeated)

    iterate_battler(1, 0) do |battler|  #Note6

      # If battler exists

      if battler.exist?

        # Set action

        battler.current_action.kind = action_type

        if battler.current_action.kind == action_id

          battler.current_action.basic = action_id

        else

          battler.current_action.skill_id = action_id

        end

        # Set action target

        if target == -2  # -2 means last enemy

          battler.current_action.decide_last_target_for_actor

        elsif target == -1 # -1 means random enemy

          battler.current_action.decide_random_target_for_actor

        elsif target >= 0

          battler.current_action.target_index = target

        end

        # Set force flag

        # If action is valid

        if battler.current_action.valid? 

          battler.current_action.forcing = true

          # Set battler being forced into action

          $game_temp.forcing_battler = battler

          # End

          return false

        end

      end

    end

    # Continue

    return true

  end

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

  # * Battler Iterator (consider entire troop and entire party)

  #     parameter1 : If 0, enemy; if 1, actor

  #     parameter2 : If 0 or above, index; if -1, all

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

  def iterate_battler(parameter1, parameter2)

    # If enemy

    if parameter1 == 0

      # Call enemy iterator

      iterate_enemy(parameter2) do |enemy|

        yield enemy

      end

    # If actor

    else

      # If entire party

      if parameter2 == -1

        # Loop for entire party

        for actor in $game_party.actors

          # Evaluate block

          yield actor

        end

      # If single actor (N exposed)

      else

        # Get actor

        actor = $game_party.actors[parameter2]

        # Evaluate block

        yield actor if actor != nil

      end

    end

  end

end
Code:
# This class is used to allocate a storage for grathe's code.

# it stores what the contents of each line is, but not where each one redirects to.

 

 

class Grathe_Code_Bank

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

  # * Object Initialization

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

  def initialize

    @data = []

    

    #Note 10

    @data[1] = 111

    @data[2] = 83

    @data[3] = 105

    @data[4] = 107

    @data[5] = 87

    @data[6] = 105

    @data[7] = 86

    @data[8] = 105

    

    

    

    

  end

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

  # * Get Variable

  #     variable_id : variable ID

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

  def [](line_number)

    if @data[line_number] != nil

      return @data[line_number]

    else

      return 0

    end

  end

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

  # * Set Variable

  #     variable_id : variable ID

  #     value       : the variable's value

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

  def []=(line_number, value)

    if line_number <= 100

      @data[line_number] = value

    end

  end

end

 

 

 

 

 

 

# This class is used to allocate a storage for grathe's code.

# This one stores where each if statement redirects to.

 

 

class Grathe_Code_Bank2

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

  # * Object Initialization

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

  def initialize

    @data = []

    

    #Note11

    @data[1] = 4

    @data[3] = 1

    @data[4] = 7

    @data[6] = 4

    @data[8] = 1

    

  end

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

  # * Get Variable

  #     variable_id : variable ID

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

  def [](line_number)

    if @data[line_number] != nil

      return @data[line_number]

    else

      return 0

    end

  end

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

  # * Set Variable

  #     variable_id : variable ID

  #     value       : the variable's value

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

  def []=(line_number, value)

    if line_number <= 100

      @data[line_number] = value

    end

  end

end
Code:
class Scene_grathe_code

  

  def initialize

    @current_line = 1

    @selected_item=85

    @item_type=0  #0 for an action, 1 for an if statement

    $choosing_line = true

    @status_window = Window_Grathe_status.new

    @left_window = Window_Grathe_code_left.new(1)

    @unused_window = Window_Grathe_unused.new(@selected_item, @item_type)

    @help_window = Window_Help.new

  end

 

  

  def main

    Graphics.transition

    loop do

      Graphics.update

      Input.update

      update

      if $scene != self

        break

      end

    end

    Graphics.freeze

    @status_window.dispose

    @left_window.dispose

    @unused_window.dispose

    @help_window.dispose

  end

 

  

  

  def update

    @unused_window.refresh(@selected_item, @item_type)

    @left_window.refresh(@current_line)

    @status_window.refresh

    if $grathe_code[@current_line] == 0

      @help_window.set_text("")

    else

      @help_window.set_text($data_items[$grathe_code[@current_line]].description)

    end

    if $choosing_line

      choose_line

    else

      choose_item

    end

  end

 

  

  def choose_item

    if @item_type == 0

      c = 83 #Note1

      d = 103 #Note2

    else

      c =105 #Note3

      d =125 #Note4

    end

    if Input.trigger?(Input::UP)

      if @selected_item > c

        @selected_item-= 1

      else

        $game_system.se_play($data_system.cursor_se)

      end

    end

    if Input.trigger?(Input::DOWN)

      if @selected_item < d

        @selected_item+= 1

      else

        $game_system.se_play($data_system.cursor_se)

      end

    end    

    if Input.trigger?(Input::LEFT)

      if @item_type == 1

        @selected_item-=22 #Note5

        @item_type=0

        $game_system.se_play($data_system.decision_se)

      else

        $game_system.se_play($data_system.buzzer_se)

      end

    end

    if Input.trigger?(Input::RIGHT)

      if@item_type == 0

        @selected_item+=22 #Note5

        @item_type = 1

        $game_system.se_play($data_system.decision_se)

      else

        $game_system.se_play($data_system.buzzer_se)

      end

    end

    if Input.trigger?(Input::B)

      $choosing_line = true

    end

    if Input.trigger?(Input::C)

      if $game_party.item_number(@selected_item) >=1 and $grathe_code[@current_line] != @selected_item

        $game_party.lose_item(@selected_item, 1)

        $grathe_code[@current_line] = @selected_item

        $game_system.se_play($data_system.equip_se)

        $choosing_line = true

      else

        $game_system.se_play($data_system.buzzer_se)

      end

    end   

    @status_window.refresh

    @left_window.refresh(@current_line)

    @unused_window.refresh(@selected_item, @item_type)

  end

  

  

  

  def choose_line

    if Input.trigger?(Input::UP) # for when up is pressed

      if @current_line > 1

        @current_line -= 1

      else

        $game_system.se_play($data_system.cursor_se)

      end

    end

    if Input.trigger?(Input::DOWN)

      if @current_line < 150

        @current_line += 1

      else

        $game_system.se_play($data_system.cursor_se)

      end

    end

    if Input.trigger?(Input::RIGHT)

      $grathe_code2[@current_line]+=1

    end

    if Input.trigger?(Input::LEFT)

      $grathe_code2[@current_line]-=1

    end

    if Input.trigger?(Input::B)

      $game_system.se_play($data_system.cancel_se)

      $scene = Scene_Menu.new(6)

      return

    end

    if Input.trigger?(Input::C)

      $choosing_line = false

    end

    @status_window.refresh

    @left_window.refresh(@current_line)

    @unused_window.refresh(@selected_item, @item_type)

  end

end
Code:
class Window_Grathe_code_left < Window_Base

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

  # * Object Initialization

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

  def initialize(selectedline)

    super(0, 64, 320, 416)

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

    self.contents.font.name = $fontface

    self.contents.font.size = $fontsize

    refresh(selectedline)

  end

  

  def refresh(selectedline)

    self.contents.clear

    if $choosing_line

      bitmap = RPG::Cache.picture('Highlighter')

      self.contents.blt(-19,-82, bitmap, Rect.new(0, 0, 640, 640))

    end

    determine_line(selectedline-4,16)

    determine_line(selectedline-3,48)

    determine_line(selectedline-2,80)

    determine_line(selectedline-1,112)

    determine_line(selectedline,176)

    determine_line(selectedline+1,240)

    determine_line(selectedline+2,272)

    determine_line(selectedline+3,304)

    determine_line(selectedline+4,336)

  end

  

  def determine_line(linetodraw,y)

    if linetodraw<=0 or linetodraw > 150

      return true

    else

      self.contents.draw_text (16, y, 48, 32, linetodraw.to_s)

      draw_item_name($data_items[$grathe_code[linetodraw]],58,y)

      self.contents.draw_text(250,y,64,32, $grathe_code2[linetodraw].to_s)

    end

  end

end
Note: This window doesn't do anything currently, but its a goodplace to put.... something.
Code:
class Window_Grathe_status < Window_Base

  def initialize

    super(320, 64, 320, 180)

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

    self.contents.font.name = $fontface

    self.contents.font.size = $fontsize

    refresh

  end

  def refresh

  end

end
Code:
class Window_Grathe_unused < Window_Base

  def initialize(x,y)

    super(320, 244, 320, 236)

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

    self.contents.font.name = $fontface

    self.contents.font.size = $fontsize

    @llega = 0

    refresh(x,y)

  end

  

  

  def refresh(a,b)

    self.contents.clear

    if b == 0 #action

      c = 83   #Note 1

      d = 103 #Note 2

    else #a redirect

      c =105  #Note 3

      d =125  #Note 4

    end

    if !$choosing_line

      bitmap = RPG::Cache.picture('Highlighter')

      self.contents.blt(-19,-164, bitmap, Rect.new(0, 0, 640, 640))

    end

    if b #drawing actions, items 83-103

      draw_item_name($data_items[a], 64, 96)

      self.contents.draw_text(16,96,64,32, $game_party.item_number(a).to_s)

      if a-1>=c  # Ensures it doesn't draw an item that isn't of the right type.

        draw_item_name($data_items[a-1], 64, 48)

        self.contents.draw_text(16,48,64,32, $game_party.item_number(a-1).to_s)

        if a-2>=c

          draw_item_name($data_items[a-2], 64, 16)

          self.contents.draw_text(16,16,64,32, $game_party.item_number(a-2).to_s)

        end

      end

      if a+1<=d

        draw_item_name($data_items[a+1], 64, 144)

        self.contents.draw_text(16,144,64,32, $game_party.item_number(a+1).to_s)

        if a+2<=d

          draw_item_name($data_items[a+2], 64, 176)

          self.contents.draw_text(16,176,64,32, $game_party.item_number(a+2).to_s)

        end

      end

    end

  end

end



Instructions

Place each of the above scripts in the game, I know that six is quite a few, but, they are all needed. Also download the attached file "highlighter" and put it in the pictures folder.
To bring up the AI editing screen, simply use the line $scene = Scene_grathe_code.new

Also, in scene_title, after command_new_game and in battle_test, insert these lines
Code:
    $grathe_code =Grathe_Code_Bank.new

    $grathe_code2 =Grathe_Code_Bank2.new

    $grathe_AI = GratheAI.new

in Scene_load add these lines after all of the marshal.load
Code:
    $grathe_code           = Marshal.load(file)

    $grathe_code2          = Marshal.load(file)

    $grathe_AI     = Marshal.load(file)

In Scene_save, add these after all of the Marshal.dump
Code:
    Marshal.dump($grathe_code, file)

    Marshal.dump($grathe_code2, file)

    Marshal.dump($grathe_AI, file)


Also, I put various notes in the script in places that need to be customized for your specific game (my values are still in there)
Note1 This should be the number of the lowest action statement
Note2 This should be the number of the highest action statement
Note3 This should be the number of the lowest redirect statement
note4 This should be the number of the highest redirect statement
Note5 This should be the difference between the number of the lowest action statement and the number of the lowest redirect statement
Note6 Replace the 0 in this line with the location of the hero in the party (if he is 1st, keep it at 0, if he is 2nd, replace it with 1, if he is 3rd replace w/2, if he is 4th replace with 3.)
Note7 Here you have to impliment your own action lines, simply call action_passer(a,b,c)
A is 1 for a skill, and 0 for a regular action, B is the number of the skill, or for an action, 0 is attack, 1 is defend. Leave C to be -1, I can't fix it yet.
Note8 Replace the 83 with the skill you want performed upon failure of the AI.
Note9 Here is where the redirect lines are chosen, goto is a boolean, and simply make it true if you want it to redirect.
Note10 Here you can impliment the default AI. This section contains what item is in each line
Note11 Here you can impliment the default AI. This section contains where each line redirects to.

To add potential lines, dedicate a continuous chunk of 20 or so (more if you want) lines for actions, and THE SAME NUMBER for redirect statements. Name and description them appropriately, and then customize them where Note10 and Note11 are in the script.


-important-
Due to the myriad of Custom battle systems, the installation requires a little bit of scripting knowledge, have it so that when the character's turn comes up, execute $grathe_AI.main instead of executing his turn.

Also, this script uses variables 70-75, so don't use them in the game.

FAQ

Q.) do you plan on re-writing the script so it isn't such a PITA to impliment?
A.) I will consider it, just remember, it only needs to be implimented once.

Q.) Can I add my own lines?
A.) Yes, look above

Q.) Does it support more than one character?
A.) Not at this time, but you can have other characters that are not AI controlled.

Q.) OMG! CAN I HAVE YOUR BABIES?
A.) No, and if you take them anyway, you will be charged with kidnapping.

Compatibility

Currently unknown.... but it does use variables 70-75, so its not compatible with anything else that uses em.


Author's Notes

If you are having trouble figuring out how to modify a specific battle system to skip the guy's turn and instead use the AI, I can help with that.
 

kaileb

Member

Thats so coooool I just have a ?. ok when I try to play my game with the script it says "Unable to find graphics/Gradients/014-reds01." I dont get it ive looked all over the original but nothing says that! PLZ HELP!
:'( ??? ???
 
That is quite interesting, I don't see why my script would produce that error.

Anyway, that error means that you set your gradient to something that doesn't exist.  Just change your gradient to something else that does exist.
 
No offense but why does everyone insist on using low variables.  If your going to take away my variables and/or switches do it in the 500s or something where I don't have any used.  I really don't like having to go through scripts and change all sorts of variables and switches.  I'd like to try your script out but I'm afraid until the variables are changed higher I won't be able too.
 
The reason I used the game variables, was so that I could give a character skills that influenced the AI's behavior.  But in hindsight, it was a bad idea to do that.  I'll make a new version of the script, and it will include various new features, such as multiple actions in one turn, and remove the reliance on game variables.
 

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