User Customizable AI script

0 Members and 1 Guest are viewing this topic.

**
Rep: +0/-0Level 87
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

Spoiler for "Main AI":
Code: [Select]
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
Spoiler for "memory":
Code: [Select]
# 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
Spoiler for "Interface to edit AI":
Code: [Select]
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
Spoiler for "Window1":
Code: [Select]
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
Spoiler for "Window2":
Note: This window doesn't do anything currently, but its a goodplace to put.... something.
Code: [Select]
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
Spoiler for "Window3":
Code: [Select]
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: [Select]
    $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: [Select]
    $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: [Select]
    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.


Demo
http://hosted.filefront.com/lordpidey/   (note that this is a demo of alpha2, and a few notable improvements have been made to the in game-editor.



*edit* whoops, as a later poster pointed out I formed the link to the screenshot incorrectly, my bad.
« Last Edit: March 21, 2007, 09:37:34 PM by pidey »

*
Full Metal Mod - He will pillage your women!
Rep:
Level 93
The RGSS Dude
Why...are...there...no...replies...?

*claps*

This is something I could never get myself to sit down and do, props. :)
"The wonderful thing about Tiggers
Is Tiggers are wonderful things
Their tops are made out of rubber
Their bottoms are made out of springs

They’re bouncy, trouncy, flouncy, pouncy
Fun, fun, fun, fun, fun!
But the most wonderful thing about Tiggers
Is I’m the only one, I’m the only one."

*
? ? ? ? ? ? ? ? ? The nice kind of alien~
Rep:
Level 92
Martian - Occasionally kind
Great job Pidey and thanks for sharing.

Edit:
The link to the screenshot is not right. Use this instead:
Code: [Select]
[url]http://i12.photobucket.com/albums/a231/pidey/aidemopic.png[/url]
Or this:
Code: [Select]
[img]http://i12.photobucket.com/albums/a231/pidey/aidemopic.png[/img]

The first creates a link and the second shows the image in the post
« Last Edit: March 21, 2007, 07:01:03 AM by Zeriab »

***
Rep:
Level 88
Gone.
Excellent *gives cookie*
Good Bye. RMRK you were cool while I wasn't there.

**
Rep:
Level 87
RIP w-hat the fork
*takes cookie from above post*

Can this script allow me to switch between the basic "approach" and "random" every so many seconds?
Huge sig is huuuuge.

**
Rep: +0/-0Level 87
*takes cookie from above post*

Can this script allow me to switch between the basic "approach" and "random" every so many seconds?


No stealing my cookie, besides, the cookie is almost six months old, its not edible anymore.

Further, let me understand what you are asking, you want a character to SOMETIMES use the AI and SOMETIMES be controled by the character?  Thats easy enough to do.   Simply only execute $grathe_AI.main when you want him to be controled automatically.

**
Rep:
Level 87
RIP w-hat the fork
not exactly, i want him to move random, then try to walk towards the player. and cycle through this every 5 seconds or so.
Huge sig is huuuuge.

*
Rep:
Level 97
2014 Most Unsung Member2014 Best RPG Maker User - Engine2013 Best RPG Maker User (Scripting)2012 Most Mature Member2012 Favorite Staff Member2012 Best RPG Maker User (Scripting)2012 Best MemberSecret Santa 2012 ParticipantProject of the Month winner for July 20092011 Best Use of Avatar and Signature Space2011 Best RPG Maker User (Scripting)2011 Most Mature Member2011 Favourite Staff Member2011 Best Veteran2010 Best RPG Maker User (Scripting)2010 Most Mature Member
I was under the impression this was battle AI, not event AI. I could be very wrong.

**
Rep: +0/-0Level 87
Yeah, sorry, this is a battle AI.  It has nothing to do with movement.

*
Rep: +0/-0Level 10
RMRK Junior
Previous lci.jqog.rmrk.net.xxc.te trapezius order lady era online retin-a doxycycline kamagra jelly voveran without a prescription flying psychosis, <a href="http://antonioscollegestation.com/lady-era/">lady era</a> <a href="http://circulateindia.com/retin-a/">retin-a</a> <a href="http://vowsbridalandformals.com/doxycycline/">doxycycline hyclate 100mg</a> <a href="http://wellnowuc.com/buy-kamagra-online/">buy kamagra online</a> <a href="http://recipiy.com/voveran/">voveran for sale</a> constipation, part: http://antonioscollegestation.com/lady-era/ lady era canada http://circulateindia.com/retin-a/ retin a http://vowsbridalandformals.com/doxycycline/ buy doxycycline http://wellnowuc.com/buy-kamagra-online/ kamagra in canada http://recipiy.com/voveran/ voveran voveran for sale quetiapine scrotal incomplete.

*
Rep: +0/-0Level 7
RMRK Junior
Percutaneous vlq.pctf.rmrk.net.fph.cf paclitaxel, cialis without prescription cialis serophene lowest price discount antabuse lioresal kamagra sinemet no prescription sinemet for sale photos; <a href="http://puresportsnetwork.com/cheap-cialis/">suppliers of cialis</a> <a href="http://robots2doss.org/cialis-uk/">cialis 20mg</a> <a href="http://gormangreen.com/serophene/">cheap serophene</a> order serophene online <a href="http://theatreghost.com/antabuse/">antabuse</a> <a href="http://infiniterotclothing.com/lioresal-online/">lioresal online</a> <a href="http://vowsbridalandformals.com/kamagra/">acheter du viagra</a> <a href="http://myonlineslambook.com/sinemet/">online sinemet</a> hyphaema, http://puresportsnetwork.com/cheap-cialis/ cialis cost http://robots2doss.org/cialis-uk/ tadalafil online http://gormangreen.com/serophene/ cheap serophene http://theatreghost.com/antabuse/ buy antabuse http://infiniterotclothing.com/lioresal-online/ lioresal online lioresal online http://vowsbridalandformals.com/kamagra/ kamagra oral http://myonlineslambook.com/sinemet/ online sinemet satisfy microthrombi.