mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
Compare commits
3 Commits
ef5e023ae0
...
e11e62272c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e11e62272c | ||
|
|
51f98b9cc7 | ||
|
|
318ff90d8d |
BIN
Audio/BGM/SSANNE.ogg
Normal file
BIN
Audio/BGM/SSANNE.ogg
Normal file
Binary file not shown.
BIN
Audio/BGM/bicycle.mp3
Normal file
BIN
Audio/BGM/bicycle.mp3
Normal file
Binary file not shown.
16
Credits.txt
16
Credits.txt
@@ -107,9 +107,9 @@ casinoluck<s>ymirbot
|
||||
|
||||
|
||||
###################################
|
||||
### Custom Pok?dex entries ###
|
||||
### Custom Pokedex entries ###
|
||||
###################################
|
||||
### Pok?dex entries quality control (Unown)
|
||||
### Pokedex entries quality control (Unown)
|
||||
luvischlo<s>char_latte3412<s>strawbearycandy
|
||||
bobosmith01<s>griddle<s>.izik
|
||||
knilk<s>lordjoostmeister<s>.realthree
|
||||
@@ -127,6 +127,10 @@ Maruno (http://pokemonessentials.wikia.com/wiki/Pok%C3%A9mon_Essentials_Wiki)
|
||||
###########################################################
|
||||
Playtesting was done by various members of the Discord channel.
|
||||
Special thanks to all of you!
|
||||
|
||||
Elite 4 rematch teams
|
||||
duskrd<s>anaconja
|
||||
|
||||
###########################################################
|
||||
### Graphics #
|
||||
###########################################################
|
||||
@@ -140,6 +144,14 @@ Nintendo
|
||||
GameFreak
|
||||
|
||||
|
||||
########################
|
||||
### Translations #
|
||||
########################
|
||||
French translation:
|
||||
anthonygourmand
|
||||
locpic_
|
||||
blood.wolf58 (Willi)
|
||||
|
||||
#######################################################################
|
||||
The following ressources were also used
|
||||
with their respective authors' consent
|
||||
|
||||
BIN
Data/.DS_Store
vendored
BIN
Data/.DS_Store
vendored
Binary file not shown.
11
Data/.idea/Data.iml
generated
Normal file
11
Data/.idea/Data.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="RUBY_MODULE" version="4">
|
||||
<component name="ModuleRunConfigurationManager">
|
||||
<shared />
|
||||
</component>
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
Data/.idea/modules.xml
generated
Normal file
8
Data/.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/Data.iml" filepath="$PROJECT_DIR$/.idea/Data.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
7
Data/.idea/vcs.xml
generated
Normal file
7
Data/.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/Scripts" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -5,10 +5,13 @@
|
||||
#==============================================================================#
|
||||
module Settings
|
||||
# The version of your game. It has to adhere to the MAJOR.MINOR.PATCH format.
|
||||
GAME_VERSION = '6.6.2'
|
||||
GAME_VERSION_NUMBER = "6.6.2"
|
||||
GAME_VERSION = '6.7.0'
|
||||
GAME_VERSION_NUMBER = "6.7.0"
|
||||
LATEST_GAME_RELEASE = "6.6"
|
||||
|
||||
KANTO = GAME_ID == :IF_KANTO
|
||||
HOENN = GAME_ID == :IF_HOENN
|
||||
|
||||
POKERADAR_LIGHT_ANIMATION_RED_ID = 17
|
||||
POKERADAR_LIGHT_ANIMATION_GREEN_ID = 18
|
||||
POKERADAR_HIDDEN_ABILITY_POKE_CHANCE = 32
|
||||
@@ -33,7 +36,7 @@ module Settings
|
||||
BATTLERS_FOLDER = "Graphics/Battlers/Autogens/"
|
||||
DOWNLOADED_SPRITES_FOLDER = "Graphics/temp/"
|
||||
DEFAULT_SPRITE_PATH = "Graphics/Battlers/Special/000.png"
|
||||
CREDITS_FILE_PATH = "Data/sprites/Sprite Credits.csv"
|
||||
CREDITS_FILE_PATH = "Data/sprites/Sprite_Credits.csv"
|
||||
VERSION_FILE_PATH = "Data/VERSION"
|
||||
CUSTOM_SPRITES_FILE_PATH = "Data/sprites/CUSTOM_SPRITES"
|
||||
BASE_SPRITES_FILE_PATH = "Data/sprites/BASE_SPRITES"
|
||||
@@ -66,9 +69,13 @@ module Settings
|
||||
SPRITES_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/infinitefusion-e18/main/Data/sprites/CUSTOM_SPRITES"
|
||||
BASE_SPRITES_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/infinitefusion-e18/main/Data/sprites/BASE_SPRITES"
|
||||
|
||||
CREDITS_FILE_URL = "https://infinitefusion.net/Sprite Credits.csv"
|
||||
CREDITS_FILE_URL = "https://infinitefusion.net/customsprites/Sprite_Credits.csv"
|
||||
CUSTOM_DEX_FILE_URL = "https://raw.githubusercontent.com/infinitefusion/pif-downloadables/refs/heads/master/dex.json"
|
||||
|
||||
|
||||
SECRETBASE_UPLOAD_URL = "http://secretbases-upload.pkmninfinitefusion.workers.dev"
|
||||
SECRETBASE_DOWNLOAD_URL = "https://secretbase-download.pkmninfinitefusion.workers.dev"
|
||||
|
||||
STARTUP_MESSAGES = ""
|
||||
|
||||
LEVEL_CAPS=[12,22,26,35,38,45,51,54,62,62,63,64,64,65,67,68]
|
||||
@@ -175,12 +182,19 @@ module Settings
|
||||
# always inherit egg moves from its father.
|
||||
BREEDING_CAN_INHERIT_EGG_MOVES_FROM_MOTHER = (MECHANICS_GENERATION >= 6)
|
||||
|
||||
|
||||
KANTO_STARTERS = [:BULBASAUR, :CHARMANDER, :SQUIRTLE]
|
||||
JOHTO_STARTERS = [:CHIKORITA, :CYNDAQUIL, :TOTODILE]
|
||||
HOENN_STARTERS = [:TREECKO, :TORCHIC, :MUDKIP]
|
||||
SINNOH_STARTERS = [:TURTWIG, :CHIMCHAR, :PIPLUP]
|
||||
KALOS_STARTERS = [:CHESPIN, :FENNEKIN, :FROAKIE]
|
||||
|
||||
DEFAULT_STARTERS = Settings::GAME_ID == :IF_KANTO ? KANTO_STARTERS : HOENN_STARTERS
|
||||
|
||||
|
||||
GRASS_STARTERS = [:BULBASAUR,:CHIKORITA,:TREECKO,:TURTWIG,:CHESPIN]
|
||||
FIRE_STARTERS = [:CHARMANDER,:CYNDAQUIL, :TORCHIC, :CHIMCHAR, :FENNEKIN]
|
||||
WATER_STARTERS = [:SQUIRTLE, :TOTODILE, :MUDKIP, :PIPLUP, :FROAKIE]
|
||||
|
||||
#=============================================================================
|
||||
|
||||
@@ -345,7 +359,7 @@ module Settings
|
||||
# Dex list, no matter which region the player is currently in.
|
||||
def self.pokedex_names
|
||||
return [
|
||||
# [_INTL("Kanto Pokédex"), 0]
|
||||
# ["Kanto Pokédex", 0]
|
||||
]
|
||||
end
|
||||
|
||||
@@ -543,11 +557,15 @@ module Settings
|
||||
# file in the Data folder. Edit only if you have 2 or more languages to choose
|
||||
# from.
|
||||
LANGUAGES = [
|
||||
# ["English", "english.dat"],
|
||||
# ["Deutsch", "deutsch.dat"]
|
||||
["English", "english.dat"],
|
||||
["Français", "french.dat"]
|
||||
]
|
||||
|
||||
|
||||
#Experimental
|
||||
REMOTE_BATTLES_CONTROL = false
|
||||
REMOTE_NPC_DIALOG = false
|
||||
REMOTE_BATTLE_CONTROL_SERVER_URL = "http://127.0.0.1:5000/choose_move"
|
||||
REMOTE_NPC_DIALOG_SERVER_URL = "http://127.0.0.1:5000"
|
||||
#Technical
|
||||
SPRITE_CACHE_MAX_NB=100
|
||||
NEWEST_SPRITEPACK_MONTH = 12
|
||||
@@ -576,7 +594,7 @@ module Settings
|
||||
"speech hgss 18",
|
||||
"speech hgss 19",
|
||||
"speech hgss 20",
|
||||
"speech pl 18"
|
||||
"speech pl 18",
|
||||
]
|
||||
|
||||
# Available menu frames. These are graphic files in "Graphics/Windowskins/".
|
||||
|
||||
@@ -3,42 +3,42 @@
|
||||
# HTTP utility functions
|
||||
#
|
||||
#############################
|
||||
#
|
||||
|
||||
def pbPostData(url, postdata, filename=nil, depth=0)
|
||||
if url[/^http:\/\/([^\/]+)(.*)$/]
|
||||
host = $1
|
||||
path = $2
|
||||
path = "/" if path.length==0
|
||||
userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
|
||||
body = postdata.map { |key, value|
|
||||
keyString = key.to_s
|
||||
valueString = value.to_s
|
||||
keyString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
|
||||
valueString.gsub!(/[^a-zA-Z0-9_\.\-]/n) { |s| sprintf('%%%02x', s[0]) }
|
||||
next "#{keyString}=#{valueString}"
|
||||
}.join('&')
|
||||
ret = HTTPLite.post_body(
|
||||
url,
|
||||
body,
|
||||
"application/x-www-form-urlencoded",
|
||||
{
|
||||
"Host" => host, # might not be necessary
|
||||
"Proxy-Connection" => "Close",
|
||||
"Content-Length" => body.bytesize.to_s,
|
||||
"Pragma" => "no-cache",
|
||||
"User-Agent" => userAgent
|
||||
}
|
||||
) rescue ""
|
||||
return ret if !ret.is_a?(Hash)
|
||||
return "" if ret[:status] != 200
|
||||
return ret[:body] if !filename
|
||||
File.open(filename, "wb"){|f|f.write(ret[:body])}
|
||||
return "" unless url =~ /^https?:\/\/([^\/]+)(.*)$/
|
||||
host = $1
|
||||
path = $2
|
||||
path = "/" if path.empty?
|
||||
|
||||
userAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.14) Gecko/2009082707 Firefox/3.0.14"
|
||||
|
||||
# Serialize as JSON
|
||||
body = serialize_json(postdata)
|
||||
|
||||
ret = HTTPLite.post_body(
|
||||
url,
|
||||
body,
|
||||
"application/json",
|
||||
{
|
||||
"Host" => host,
|
||||
"Proxy-Connection" => "Close",
|
||||
"Content-Length" => body.bytesize.to_s,
|
||||
"Pragma" => "no-cache",
|
||||
"User-Agent" => userAgent
|
||||
}
|
||||
) rescue ""
|
||||
|
||||
return "" if !ret.is_a?(Hash)
|
||||
return "" if ret[:status] != 200
|
||||
if filename
|
||||
File.open(filename, "wb") { |f| f.write(ret[:body]) }
|
||||
return ""
|
||||
end
|
||||
return ""
|
||||
ret[:body]
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbDownloadData(url, filename = nil, authorization = nil, depth = 0, &block)
|
||||
return nil if !downloadAllowed?()
|
||||
echoln "downloading data from #{url}"
|
||||
@@ -73,15 +73,21 @@ def pbDownloadToFile(url, file)
|
||||
end
|
||||
end
|
||||
|
||||
def pbPostToString(url, postdata)
|
||||
def pbPostToString(url, postdata, timeout = 30)
|
||||
safe_postdata = postdata.transform_values(&:to_s)
|
||||
begin
|
||||
data = pbPostData(url, postdata)
|
||||
return data
|
||||
rescue
|
||||
data = pbPostData(url, safe_postdata)
|
||||
return data || ""
|
||||
rescue MKXPError => e
|
||||
echoln("[Remote AI] Exception: #{e.message}")
|
||||
return ""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def pbPostToFile(url, postdata, file)
|
||||
begin
|
||||
pbPostData(url, postdata,file)
|
||||
@@ -89,7 +95,7 @@ def pbPostToFile(url, postdata, file)
|
||||
end
|
||||
end
|
||||
|
||||
def serialize_value(value)
|
||||
def serialize_value_legacy(value)
|
||||
if value.is_a?(Hash)
|
||||
serialize_json(value)
|
||||
elsif value.is_a?(String)
|
||||
@@ -102,17 +108,47 @@ end
|
||||
|
||||
|
||||
def serialize_json(data)
|
||||
#echoln data
|
||||
# Manually serialize the JSON data into a string
|
||||
parts = ["{"]
|
||||
data.each_with_index do |(key, value), index|
|
||||
parts << "\"#{key}\":#{serialize_value(value)}"
|
||||
parts << "," unless index == data.size - 1
|
||||
if data.is_a?(Hash)
|
||||
parts = ["{"]
|
||||
data.each_with_index do |(key, value), index|
|
||||
parts << "\"#{key}\":#{serialize_value(value)}"
|
||||
parts << "," unless index == data.size - 1
|
||||
end
|
||||
parts << "}"
|
||||
return parts.join
|
||||
else
|
||||
return serialize_value(data)
|
||||
end
|
||||
parts << "}"
|
||||
return parts.join
|
||||
end
|
||||
|
||||
def serialize_value(value)
|
||||
case value
|
||||
when String
|
||||
"\"#{escape_json_string(value)}\""
|
||||
when Numeric
|
||||
value.to_s
|
||||
when TrueClass, FalseClass
|
||||
value.to_s
|
||||
when NilClass
|
||||
"null"
|
||||
when Array
|
||||
"[" + value.map { |v| serialize_value(v) }.join(",") + "]"
|
||||
when Hash
|
||||
serialize_json(value)
|
||||
else
|
||||
raise "Unsupported type: #{value.class}"
|
||||
end
|
||||
end
|
||||
|
||||
def escape_json_string(str)
|
||||
# Minimal escape handling
|
||||
str.gsub(/["\\]/) { |m| "\\#{m}" }
|
||||
.gsub("\n", "\\n")
|
||||
.gsub("\t", "\\t")
|
||||
.gsub("\r", "\\r")
|
||||
end
|
||||
|
||||
|
||||
|
||||
def downloadAllowed?()
|
||||
return $PokemonSystem.download_sprites==0
|
||||
@@ -141,6 +177,42 @@ def clean_json_string(str)
|
||||
end
|
||||
|
||||
|
||||
# json.rb - lightweight JSON parser for MKXP/RGSS XP
|
||||
|
||||
# Lightweight JSON for MKXP/RGSS XP
|
||||
module JSON
|
||||
module_function
|
||||
|
||||
# Convert Ruby object (hash/array/etc) into JSON string
|
||||
def generate(obj)
|
||||
case obj
|
||||
when Hash
|
||||
"{" + obj.map { |k, v| "\"#{k}\":#{generate(v)}" }.join(",") + "}"
|
||||
when Array
|
||||
"[" + obj.map { |v| generate(v) }.join(",") + "]"
|
||||
when String, Symbol
|
||||
"\"#{obj.to_s}\""
|
||||
when TrueClass, FalseClass
|
||||
obj.to_s
|
||||
when NilClass
|
||||
"null"
|
||||
when Numeric
|
||||
obj.to_s
|
||||
else
|
||||
raise "Unsupported type #{obj.class}"
|
||||
end
|
||||
end
|
||||
|
||||
# Simple parser (not full JSON) — optional
|
||||
def parse(str)
|
||||
return nil if str.nil? || str.strip.empty?
|
||||
eval(str)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -202,6 +202,7 @@ module Game
|
||||
$PokemonMap.updateMap
|
||||
$scene = Scene_Map.new
|
||||
onLoadExistingGame()
|
||||
|
||||
end
|
||||
|
||||
# Loads and validates the map. Called when loading a saved game.
|
||||
@@ -234,9 +235,15 @@ module Game
|
||||
end
|
||||
$PokemonEncounters = PokemonEncounters.new
|
||||
$PokemonEncounters.setup($game_map.map_id)
|
||||
self.load_secret_bases if Settings::HOENN
|
||||
pbUpdateVehicle
|
||||
end
|
||||
|
||||
def self.load_secret_bases
|
||||
loader = SecretBaseLoader.new
|
||||
loader.load_visitor_bases
|
||||
end
|
||||
|
||||
# Saves the game. Returns whether the operation was successful.
|
||||
# @param save_file [String] the save file path
|
||||
# @param safe [Boolean] whether $PokemonGlobal.safesave should be set to true
|
||||
|
||||
@@ -218,6 +218,12 @@ class Scene_Map
|
||||
end
|
||||
return if $game_temp.message_window_showing
|
||||
if !pbMapInterpreterRunning?
|
||||
if $game_temp.moving_furniture
|
||||
placeFurnitureMenu() if Input.trigger?(Input::USE)
|
||||
rotate__held_furniture_left if Input.trigger?(Input::JUMPDOWN)
|
||||
rotate_held_furniture_right if Input.trigger?(Input::JUMPUP)
|
||||
end
|
||||
|
||||
if Input.trigger?(Input::USE)
|
||||
$PokemonTemp.hiddenMoveEventCalling = true
|
||||
elsif Input.trigger?(Input::BACK)
|
||||
@@ -225,7 +231,7 @@ class Scene_Map
|
||||
$game_temp.menu_calling = true
|
||||
$game_temp.menu_beep = true
|
||||
dayOfWeek = getDayOfTheWeek().to_s
|
||||
$scene.spriteset.addUserSprite(LocationWindow.new($game_map.name+ "\n"+ pbGetTimeNow.strftime("%I:%M %p") + "\n" + dayOfWeek))
|
||||
$scene.spriteset.addUserSprite(LocationWindow.new($game_map.name+ "\n"+ pbGetTimeNow.strftime(_INTL("%I:%M %p")) + "\n" + dayOfWeek))
|
||||
end
|
||||
elsif Input.trigger?(Input::SPECIAL)
|
||||
unless $game_system.menu_disabled || $game_player.moving?
|
||||
|
||||
@@ -25,11 +25,6 @@ class Game_Temp
|
||||
attr_accessor :fadestate # for sprite hashes
|
||||
attr_accessor :background_bitmap
|
||||
attr_accessor :mart_prices
|
||||
attr_accessor :unimportedSprites
|
||||
attr_accessor :nb_imported_sprites
|
||||
attr_accessor :loading_screen
|
||||
attr_accessor :custom_sprites_list
|
||||
attr_accessor :base_sprites_list
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# * Object Initialization
|
||||
@@ -57,9 +52,6 @@ class Game_Temp
|
||||
@message_window_showing = false
|
||||
@transition_processing = false
|
||||
@mart_prices = {}
|
||||
@custom_sprites_list ={}
|
||||
@base_sprites_list ={}
|
||||
|
||||
end
|
||||
|
||||
def clear_mart_prices
|
||||
|
||||
@@ -12,8 +12,8 @@ class Game_Picture
|
||||
attr_reader :number # picture number
|
||||
attr_accessor :name # file name
|
||||
attr_reader :origin # starting point
|
||||
attr_reader :x # x-coordinate
|
||||
attr_reader :y # y-coordinate
|
||||
attr_accessor :x # x-coordinate
|
||||
attr_accessor :y # y-coordinate
|
||||
attr_accessor :zoom_x # x directional zoom rate
|
||||
attr_accessor :zoom_y # y directional zoom rate
|
||||
attr_accessor :opacity # opacity level
|
||||
|
||||
@@ -25,7 +25,10 @@ class Game_Character
|
||||
attr_reader :move_speed
|
||||
attr_accessor :walk_anime
|
||||
attr_writer :bob_height
|
||||
attr_accessor :under_everything
|
||||
attr_accessor :under_everything #under even grass
|
||||
attr_accessor :under_player #always under the player, but over grass, etc.
|
||||
attr_accessor :direction_fix
|
||||
attr_accessor :always_on_top
|
||||
|
||||
def initialize(map = nil)
|
||||
@map = map
|
||||
@@ -77,6 +80,7 @@ class Game_Character
|
||||
@locked = false
|
||||
@prelock_direction = 0
|
||||
@under_everything=false
|
||||
@under_player = false
|
||||
@forced_z=nil
|
||||
end
|
||||
|
||||
@@ -339,6 +343,7 @@ class Game_Character
|
||||
|
||||
def screen_z(height = 0)
|
||||
return -1 if @under_everything
|
||||
return 0 if @under_player
|
||||
return 999 if @always_on_top
|
||||
return @forced_z if @forced_z
|
||||
z = screen_y_ground
|
||||
@@ -354,6 +359,17 @@ class Game_Character
|
||||
return z + ((height > Game_Map::TILE_HEIGHT) ? Game_Map::TILE_HEIGHT - 1 : 0)
|
||||
end
|
||||
|
||||
def opposite_direction
|
||||
case @direction
|
||||
when DIRECTION_LEFT; return DIRECTION_RIGHT
|
||||
when DIRECTION_RIGHT; return DIRECTION_LEFT
|
||||
when DIRECTION_UP; return DIRECTION_DOWN
|
||||
when DIRECTION_DOWN; return DIRECTION_UP
|
||||
else
|
||||
return DIRECTION_ALL
|
||||
end
|
||||
end
|
||||
|
||||
#=============================================================================
|
||||
# Movement
|
||||
#=============================================================================
|
||||
@@ -899,6 +915,27 @@ class Game_Character
|
||||
@direction_fix = last_direction_fix
|
||||
end
|
||||
|
||||
def jump_forward
|
||||
case $game_player.direction
|
||||
when DIRECTION_DOWN
|
||||
x_direction = 0
|
||||
y_direction = 1
|
||||
when DIRECTION_UP
|
||||
x_direction = 0
|
||||
y_direction = -1
|
||||
when DIRECTION_LEFT
|
||||
x_direction = -1
|
||||
y_direction = 0
|
||||
when DIRECTION_RIGHT
|
||||
x_direction = 1
|
||||
y_direction = 0
|
||||
else
|
||||
x_direction = 0
|
||||
y_direction = 0
|
||||
end
|
||||
jump(x_direction, y_direction)
|
||||
end
|
||||
|
||||
def jump(x_plus, y_plus)
|
||||
if x_plus != 0 || y_plus != 0
|
||||
if x_plus.abs > y_plus.abs
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
class Game_Event < Game_Character
|
||||
attr_reader :map_id
|
||||
attr_reader :trigger
|
||||
attr_accessor :trigger
|
||||
attr_reader :list
|
||||
attr_reader :starting
|
||||
attr_reader :tempSwitches # Temporary self-switches
|
||||
attr_reader :character_name
|
||||
attr_accessor :need_refresh
|
||||
attr_accessor :opacity
|
||||
attr_accessor :through
|
||||
|
||||
def initialize(map_id, event, map=nil)
|
||||
super(map)
|
||||
|
||||
@@ -33,40 +33,34 @@ class Game_Player < Game_Character
|
||||
return moving? && !@move_route_forcing && pbCanRun?
|
||||
end
|
||||
|
||||
#Override the player's graphics
|
||||
# Path from Graphics/Characters/player/
|
||||
def setPlayerGraphicsOverride(path)
|
||||
@defaultCharacterName=path
|
||||
|
||||
end
|
||||
def removeGraphicsOverride
|
||||
@defaultCharacterName = ""
|
||||
end
|
||||
|
||||
def hasGraphicsOverride?
|
||||
return @defaultCharacterName!=""
|
||||
end
|
||||
|
||||
def character_name
|
||||
@defaultCharacterName = "" if !@defaultCharacterName
|
||||
return @defaultCharacterName if @defaultCharacterName!=""
|
||||
return @defaultCharacterName if hasGraphicsOverride?
|
||||
if !@move_route_forcing && $Trainer.character_ID>=0
|
||||
meta = GameData::Metadata.get_player($Trainer.character_ID)
|
||||
if meta && !$PokemonGlobal.bicycle && !$PokemonGlobal.diving && !$PokemonGlobal.surfing
|
||||
charset = 1 # Display normal character sprite
|
||||
|
||||
|
||||
player_is_moving = moving?
|
||||
if pbCanRun? && (player_is_moving || @wasmoving) && Input.dir4!=0 && meta[4] && meta[4]!=""
|
||||
charset = 4 # Display running character sprite
|
||||
end
|
||||
|
||||
newCharName = pbGetPlayerCharset(meta,charset)
|
||||
|
||||
if newCharName
|
||||
# echoln caller
|
||||
# echoln newCharName
|
||||
# echoln "moving: " + moving?.to_s
|
||||
# echoln "was moving: " + @wasmoving.to_s
|
||||
#
|
||||
# echoln "can run: " + pbCanRun?.to_s
|
||||
# echoln "Input.dir4 " + Input.dir4.to_s
|
||||
#
|
||||
#
|
||||
# echoln (moving? || @wasmoving)
|
||||
# echoln charset
|
||||
# echoln ""
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
@character_name = newCharName if newCharName
|
||||
@wasmoving = player_is_moving
|
||||
end
|
||||
|
||||
@@ -127,7 +127,9 @@ class Sprite_Wearable < RPG::Sprite
|
||||
end
|
||||
|
||||
def update(action, filename,color)
|
||||
|
||||
@sprite.opacity = @player_sprite.opacity if @wearableBitmap
|
||||
@sprite.opacity=0 if $game_player.hasGraphicsOverride?
|
||||
if filename != @filename || color != @color
|
||||
if pbResolveBitmap(filename)
|
||||
#echoln pbResolveBitmap(filename)
|
||||
|
||||
@@ -60,6 +60,13 @@ class Sprite_Player < Sprite_Character
|
||||
@charbitmap.bitmap.clone #nekkid sprite
|
||||
baseBitmap = @charbitmap.bitmap.clone #nekkid sprite
|
||||
|
||||
if $game_player.hasGraphicsOverride?
|
||||
@hair.update(@character_name, "", 0) if @hair
|
||||
@hat.update(@character_name, "", 0) if @hat
|
||||
@hat2.update(@character_name, "", 0) if @hat2
|
||||
return baseBitmap
|
||||
end
|
||||
|
||||
outfitFilename = getOverworldOutfitFilename($Trainer.clothes, @character_name) #
|
||||
outfitFilename = getOverworldOutfitFilename(Settings::PLAYER_TEMP_OUTFIT_FALLBACK) if !pbResolveBitmap(outfitFilename)
|
||||
hairFilename = getOverworldHairFilename($Trainer.hair)
|
||||
|
||||
@@ -78,6 +78,18 @@ class TilemapRenderer
|
||||
|
||||
},
|
||||
|
||||
5 => { #Rustboro
|
||||
996 => "flowers_orange[10]",
|
||||
991 => "flowers_pink[10]",
|
||||
999 => "flowers_yellow[10]",
|
||||
1007 => "flowers_blue[10]",
|
||||
1015 => "flowers_purple[10]",
|
||||
1023 => "flowers_red[10]",
|
||||
1031 => "flowers_grey[10]",
|
||||
1039 => "flowers_white[10]",
|
||||
|
||||
},
|
||||
|
||||
6 => { #Dewford Town
|
||||
|
||||
#water cliffs
|
||||
@@ -92,7 +104,8 @@ class TilemapRenderer
|
||||
},
|
||||
|
||||
7 => { #Sea Route
|
||||
|
||||
#water rocks
|
||||
1173 => "water_rock_medium[15]",
|
||||
#water cliffs
|
||||
1363 => "water_rock10", 1364 => "water_rock11",
|
||||
1389 => "water_rock01", 1391 => "water_rock09",
|
||||
@@ -154,6 +167,38 @@ class TilemapRenderer
|
||||
881 => "tree_sway_single_6",
|
||||
|
||||
|
||||
866 => "tree_sway_group_1",
|
||||
867 => "tree_sway_group_2",
|
||||
874 => "tree_sway_group_3",
|
||||
875 => "tree_sway_group_4",
|
||||
},
|
||||
|
||||
5 => { #Rustboro
|
||||
#trees
|
||||
864 => "tree_sway_single_1",
|
||||
865 => "tree_sway_single_2",
|
||||
872 => "tree_sway_single_3",
|
||||
873 => "tree_sway_single_4",
|
||||
880 => "tree_sway_single_5",
|
||||
881 => "tree_sway_single_6",
|
||||
|
||||
|
||||
866 => "tree_sway_group_1",
|
||||
867 => "tree_sway_group_2",
|
||||
874 => "tree_sway_group_3",
|
||||
875 => "tree_sway_group_4",
|
||||
},
|
||||
|
||||
9 => { #Route Forest
|
||||
#trees
|
||||
864 => "tree_sway_single_1",
|
||||
865 => "tree_sway_single_2",
|
||||
872 => "tree_sway_single_3",
|
||||
873 => "tree_sway_single_4",
|
||||
880 => "tree_sway_single_5",
|
||||
881 => "tree_sway_single_6",
|
||||
|
||||
|
||||
866 => "tree_sway_group_1",
|
||||
867 => "tree_sway_group_2",
|
||||
874 => "tree_sway_group_3",
|
||||
|
||||
@@ -129,22 +129,49 @@ class AnimatedBitmap
|
||||
@bitmap.bitmap = new_bitmap
|
||||
end
|
||||
|
||||
# def mirror
|
||||
# for x in 0..@bitmap.bitmap.width / 2
|
||||
# for y in 0..@bitmap.bitmap.height - 2
|
||||
# temp = @bitmap.bitmap.get_pixel(x, y)
|
||||
# newPix = @bitmap.bitmap.get_pixel((@bitmap.bitmap.width - x), y)
|
||||
#
|
||||
# @bitmap.bitmap.set_pixel(x, y, newPix)
|
||||
# @bitmap.bitmap.set_pixel((@bitmap.bitmap.width - x), y, temp)
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
|
||||
def mirror
|
||||
@bitmap.bitmap
|
||||
mirror_horizontally
|
||||
end
|
||||
|
||||
def mirror_horizontally
|
||||
bmp = @bitmap.bitmap
|
||||
half_width = bmp.width / 2
|
||||
height = bmp.height
|
||||
|
||||
(0...half_width).each do |x|
|
||||
(0...height).each do |y|
|
||||
left_pixel = bmp.get_pixel(x, y)
|
||||
right_pixel = bmp.get_pixel(bmp.width - 1 - x, y)
|
||||
|
||||
bmp.set_pixel(x, y, right_pixel)
|
||||
bmp.set_pixel(bmp.width - 1 - x, y, left_pixel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def mirror_vertically
|
||||
bmp = @bitmap.bitmap
|
||||
width = bmp.width
|
||||
half_height = bmp.height / 2
|
||||
|
||||
(0...half_height).each do |y|
|
||||
(0...width).each do |x|
|
||||
top_pixel = bmp.get_pixel(x, y)
|
||||
bottom_pixel = bmp.get_pixel(x, bmp.height - 1 - y)
|
||||
|
||||
bmp.set_pixel(x, y, bottom_pixel)
|
||||
bmp.set_pixel(x, bmp.height - 1 - y, top_pixel)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
# def mirror
|
||||
# @bitmap.bitmap
|
||||
# end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -396,9 +396,9 @@ def pbGetGoldString
|
||||
moneyString = _INTL("${1}", $Trainer.money.to_s_formatted)
|
||||
rescue
|
||||
if $data_system.respond_to?("words")
|
||||
moneyString = _INTL("{1} {2}", $game_party.gold, $data_system.words.gold)
|
||||
moneyString = "#{$game_party.gold} #{$data_system.words.gold}"
|
||||
else
|
||||
moneyString = _INTL("{1} {2}", $game_party.gold, Vocab.gold)
|
||||
moneyString = "#{$game_party.gold} #{Vocab.gold}"
|
||||
end
|
||||
end
|
||||
return moneyString
|
||||
@@ -474,6 +474,8 @@ def pbDisplayHeartScalesWindow(msgwindow)
|
||||
return pointswindow
|
||||
end
|
||||
|
||||
|
||||
|
||||
def pbDisplayCoinsWindow(msgwindow, goldwindow)
|
||||
coinString = ($Trainer) ? $Trainer.coins.to_s_formatted : "0"
|
||||
coinwindow = Window_AdvancedTextPokemon.new(_INTL("Coins:\n<ar>{1}</ar>", coinString))
|
||||
@@ -506,6 +508,22 @@ def pbDisplayBattlePointsWindow(msgwindow)
|
||||
return pointswindow
|
||||
end
|
||||
|
||||
def pbDisplayQuestPointsWindow(msgwindow)
|
||||
pointsString = ($Trainer) ? $Trainer.quest_points.to_s_formatted : "0"
|
||||
pointswindow = Window_AdvancedTextPokemon.new(_INTL("Quest Points:\n<ar>{1}</ar>", pointsString))
|
||||
pointswindow.setSkin("Graphics/Windowskins/goldskin")
|
||||
pointswindow.resizeToFit(pointswindow.text, Graphics.width)
|
||||
pointswindow.width = 160 if pointswindow.width <= 160
|
||||
if msgwindow.y == 0
|
||||
pointswindow.y = Graphics.height - pointswindow.height
|
||||
else
|
||||
pointswindow.y = 0
|
||||
end
|
||||
pointswindow.viewport = msgwindow.viewport
|
||||
pointswindow.z = msgwindow.z
|
||||
return pointswindow
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
#
|
||||
#===============================================================================
|
||||
@@ -594,6 +612,12 @@ def pbMessageDisplay(msgwindow, message, letterbyletter = true, commandProc = ni
|
||||
text.gsub!(/\\pog/i, "")
|
||||
text.gsub!(/\\b/i, "<c3=3050C8,D0D0C8>")
|
||||
text.gsub!(/\\r/i, "<c3=E00808,D0D0C8>")
|
||||
text.gsub!(/\\mu\[(.*?)\]/i) do
|
||||
$Trainer && isPlayerMale() ? $1 : ""
|
||||
end
|
||||
text.gsub!(/\\fu\[(.*?)\]/i) do
|
||||
$Trainer && isPlayerFemale() ? $1 : ""
|
||||
end
|
||||
text.gsub!(/\\[Ww]\[([^\]]*)\]/) {
|
||||
w = $1.to_s
|
||||
if w == ""
|
||||
@@ -632,7 +656,7 @@ def pbMessageDisplay(msgwindow, message, letterbyletter = true, commandProc = ni
|
||||
### Controls
|
||||
textchunks = []
|
||||
controls = []
|
||||
while text[/(?:\\(f|ff|ts|cl|me|se|wt|wtnp|ch)\[([^\]]*)\]|\\(g|cn|pt|ft|hs|wd|wm|op|cl|wu|\.|\||\!|\^))/i]
|
||||
while text[/(?:\\(f|ff|ts|cl|me|se|wt|wtnp|ch)\[([^\]]*)\]|\\(g|cn|pt|ft|qp|hs|wd|wm|op|cl|wu|\.|\||\!|\^))/i]
|
||||
textchunks.push($~.pre_match)
|
||||
if $~[1]
|
||||
controls.push([$~[1].downcase, $~[2], -1])
|
||||
@@ -757,6 +781,9 @@ def pbMessageDisplay(msgwindow, message, letterbyletter = true, commandProc = ni
|
||||
when "hs" # Display heartscakes
|
||||
goldwindow.dispose if goldwindow
|
||||
goldwindow = pbDisplayHeartScalesWindow(msgwindow)
|
||||
when "qp" # Display quest points
|
||||
goldwindow.dispose if goldwindow
|
||||
goldwindow = pbDisplayQuestPointsWindow(msgwindow)
|
||||
when "cn" # Display coins window
|
||||
coinwindow.dispose if coinwindow
|
||||
coinwindow = pbDisplayCoinsWindow(msgwindow, goldwindow)
|
||||
|
||||
@@ -101,7 +101,6 @@ end
|
||||
# volume -- Volume of the file, up to 100
|
||||
# pitch -- Pitch of the file, normally 100
|
||||
def pbMEPlay(param,volume=nil,pitch=nil)
|
||||
echoln param
|
||||
return if !param
|
||||
param=pbResolveAudioFile(param,volume,pitch)
|
||||
if param.name && param.name!=""
|
||||
|
||||
@@ -54,14 +54,12 @@ module GameData
|
||||
end
|
||||
|
||||
if !self::DATA.has_key?(other)
|
||||
#echoln _INTL("Unknown ID {1}.", other)
|
||||
return self::get(:PIKACHU)
|
||||
if self == GameData::Item
|
||||
return nil
|
||||
else
|
||||
return self::get(:PIKACHU)
|
||||
end
|
||||
end
|
||||
|
||||
#if other == :Species
|
||||
|
||||
# end
|
||||
|
||||
return self::DATA[other]
|
||||
end
|
||||
|
||||
|
||||
@@ -27,10 +27,16 @@ module GameData
|
||||
attr_reader :flowerYellow
|
||||
attr_reader :flowerBlue
|
||||
attr_reader :flower
|
||||
|
||||
attr_reader :trashcan
|
||||
attr_reader :sharpedoObstacle
|
||||
attr_reader :underwater #only visible when diving
|
||||
|
||||
attr_reader :secretBase_tree
|
||||
attr_reader :secretBase_cave
|
||||
attr_reader :secretBase_bush
|
||||
|
||||
|
||||
DATA = {}
|
||||
|
||||
extend ClassMethods
|
||||
@@ -82,11 +88,20 @@ module GameData
|
||||
@sharpedoObstacle = hash[:sharpedoObstacle] || false
|
||||
@underwater = hash[:underwater] || false
|
||||
|
||||
@secretBase_tree = hash[:secretBase_tree] || false
|
||||
@secretBase_cave = hash[:secretBase_cave] || false
|
||||
@secretBase_bush = hash[:secretBase_bush] || false
|
||||
|
||||
end
|
||||
|
||||
def can_surf_freely
|
||||
return @can_surf && !@waterfall && !@waterfall_crest
|
||||
end
|
||||
|
||||
def can_secret_base
|
||||
return false if Settings::GAME_ID != :IF_HOENN
|
||||
return @secretBase_tree || @secretBase_cave || @secretBase_bush
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -299,4 +314,23 @@ GameData::TerrainTag.register({
|
||||
:id_number => 28,
|
||||
:battle_environment => :underwater,
|
||||
:underwater => true,
|
||||
})
|
||||
|
||||
|
||||
GameData::TerrainTag.register({
|
||||
:id => :Secretbase_Tree,
|
||||
:id_number => 29,
|
||||
:secretBase_tree => true,
|
||||
})
|
||||
|
||||
GameData::TerrainTag.register({
|
||||
:id => :Secretbase_Cave,
|
||||
:id_number => 30,
|
||||
:secretBase_cave => true,
|
||||
})
|
||||
|
||||
GameData::TerrainTag.register({
|
||||
:id => :Secretbase_Bush,
|
||||
:id_number => 31,
|
||||
:secretBase_bush => true,
|
||||
})
|
||||
@@ -63,7 +63,7 @@ module GameData
|
||||
# return (ret) ? ret : pbResolveBitmap("Graphics/Pokemon/Eggs/000")
|
||||
# end
|
||||
def self.egg_sprite_filename(species, form)
|
||||
return "Graphics/Battlers/Eggs/000" if $PokemonSystem.use_custom_eggs
|
||||
return "Graphics/Battlers/Eggs/000" if $PokemonSystem.hide_custom_eggs
|
||||
dexNum = getDexNumberForSpecies(species)
|
||||
bitmapFileName = sprintf("Graphics/Battlers/Eggs/%d", dexNum) rescue nil
|
||||
if !pbResolveBitmap(bitmapFileName)
|
||||
|
||||
@@ -197,7 +197,8 @@ module GameData
|
||||
gym_type = GameData::Type.get(type_id)
|
||||
while true
|
||||
new_species = $game_switches[SWITCH_RANDOM_GYM_CUSTOMS] ? getSpecies(getNewCustomSpecies(old_species, customsList, bst_range)) : getSpecies(getNewSpecies(old_species, bst_range))
|
||||
if new_species.hasType?(gym_type)
|
||||
if new_species.hasType?(gym_type) || $game_switches[SWITCH_RANDOM_GYM_CUSTOMS] || $game_switches[SWITCH_LEGENDARY_MODE]
|
||||
# Note: gym Type validation is handled in-house for legendary mode
|
||||
return new_species
|
||||
end
|
||||
end
|
||||
@@ -218,6 +219,9 @@ module GameData
|
||||
end
|
||||
end
|
||||
new_species = generateRandomGymSpecies(species)
|
||||
if !new_species
|
||||
return species
|
||||
end
|
||||
if $game_switches[SWITCH_RANDOM_GYM_PERSIST_TEAMS]
|
||||
add_generated_species_to_gym_array(new_species, trainerId)
|
||||
end
|
||||
@@ -392,7 +396,7 @@ module GameData
|
||||
secondary_ability_index = pkmn.ability_index == 0 ? 1 : 0
|
||||
pkmn.ability2_index = secondary_ability_index
|
||||
pkmn.ability2 = pkmn.getAbilityList[secondary_ability_index][0]
|
||||
#print _INTL("Primary: {1}, Secondary: {2}",pkmn.ability.id, pkmn.ability2.id)
|
||||
#print "Primary: {1}, Secondary: {2}",pkmn.ability.id, pkmn.ability2.id
|
||||
end
|
||||
|
||||
pkmn.gender = pkmn_data[:gender] || ((trainer.male?) ? 0 : 1)
|
||||
|
||||
@@ -1,369 +1,5 @@
|
||||
module GameData
|
||||
class TrainerModern
|
||||
attr_reader :id
|
||||
attr_reader :id_number
|
||||
attr_reader :trainer_type
|
||||
attr_reader :real_name
|
||||
attr_reader :version
|
||||
attr_reader :items
|
||||
attr_reader :real_lose_text
|
||||
attr_reader :pokemon
|
||||
|
||||
DATA = {}
|
||||
class TrainerModern < Trainer
|
||||
DATA_FILENAME = "trainers_remix.dat"
|
||||
|
||||
SCHEMA = {
|
||||
"Items" => [:items, "*e", :Item],
|
||||
"LoseText" => [:lose_text, "s"],
|
||||
"Pokemon" => [:pokemon, "ev", :Species], # Species, level
|
||||
"Form" => [:form, "u"],
|
||||
"Name" => [:name, "s"],
|
||||
"Moves" => [:moves, "*e", :Move],
|
||||
"Ability" => [:ability, "s"],
|
||||
"AbilityIndex" => [:ability_index, "u"],
|
||||
"Item" => [:item, "e", :Item],
|
||||
"Gender" => [:gender, "e", { "M" => 0, "m" => 0, "Male" => 0, "male" => 0, "0" => 0,
|
||||
"F" => 1, "f" => 1, "Female" => 1, "female" => 1, "1" => 1 }],
|
||||
"Nature" => [:nature, "e", :Nature],
|
||||
"IV" => [:iv, "uUUUUU"],
|
||||
"EV" => [:ev, "uUUUUU"],
|
||||
"Happiness" => [:happiness, "u"],
|
||||
"Shiny" => [:shininess, "b"],
|
||||
"Shadow" => [:shadowness, "b"],
|
||||
"Ball" => [:poke_ball, "s"],
|
||||
}
|
||||
|
||||
extend ClassMethods
|
||||
include InstanceMethods
|
||||
|
||||
# @param tr_type [Symbol, String]
|
||||
# @param tr_name [String]
|
||||
# @param tr_version [Integer, nil]
|
||||
# @return [Boolean] whether the given other is defined as a self
|
||||
def self.exists?(tr_type, tr_name, tr_version = 0)
|
||||
validate tr_type => [Symbol, String]
|
||||
validate tr_name => [String]
|
||||
key = [tr_type.to_sym, tr_name, tr_version]
|
||||
return !self::DATA[key].nil?
|
||||
end
|
||||
|
||||
# @param tr_type [Symbol, String]
|
||||
# @param tr_name [String]
|
||||
# @param tr_version [Integer, nil]
|
||||
# @return [self]
|
||||
def self.get(tr_type, tr_name, tr_version = 0)
|
||||
validate tr_type => [Symbol, String]
|
||||
validate tr_name => [String]
|
||||
key = [tr_type.to_sym, tr_name, tr_version]
|
||||
raise "Unknown trainer #{tr_type} #{tr_name} #{tr_version}." unless self::DATA.has_key?(key)
|
||||
return self::DATA[key]
|
||||
end
|
||||
|
||||
# @param tr_type [Symbol, String]
|
||||
# @param tr_name [String]
|
||||
# @param tr_version [Integer, nil]
|
||||
# @return [self, nil]
|
||||
def self.try_get(tr_type, tr_name, tr_version = 0)
|
||||
validate tr_type => [Symbol, String]
|
||||
validate tr_name => [String]
|
||||
key = [tr_type.to_sym, tr_name, tr_version]
|
||||
return (self::DATA.has_key?(key)) ? self::DATA[key] : nil
|
||||
end
|
||||
|
||||
def self.list_all()
|
||||
return self::DATA
|
||||
end
|
||||
|
||||
def initialize(hash)
|
||||
@id = hash[:id]
|
||||
@id_number = hash[:id_number]
|
||||
@trainer_type = hash[:trainer_type]
|
||||
@real_name = hash[:name] || "Unnamed"
|
||||
@version = hash[:version] || 0
|
||||
@items = hash[:items] || []
|
||||
@real_lose_text = hash[:lose_text] || "..."
|
||||
@pokemon = hash[:pokemon] || []
|
||||
@pokemon.each do |pkmn|
|
||||
GameData::Stat.each_main do |s|
|
||||
pkmn[:iv][s.id] ||= 0 if pkmn[:iv]
|
||||
pkmn[:ev][s.id] ||= 0 if pkmn[:ev]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# @return [String] the translated name of this trainer
|
||||
def name
|
||||
return pbGetMessageFromHash(MessageTypes::TrainerNames, @real_name)
|
||||
end
|
||||
|
||||
# @return [String] the translated in-battle lose message of this trainer
|
||||
def lose_text
|
||||
return pbGetMessageFromHash(MessageTypes::TrainerLoseText, @real_lose_text)
|
||||
end
|
||||
|
||||
def replace_species_with_placeholder(species)
|
||||
case species
|
||||
when Settings::RIVAL_STARTER_PLACEHOLDER_SPECIES
|
||||
return pbGet(Settings::RIVAL_STARTER_PLACEHOLDER_VARIABLE)
|
||||
when Settings::VAR_1_PLACEHOLDER_SPECIES
|
||||
return pbGet(1)
|
||||
when Settings::VAR_2_PLACEHOLDER_SPECIES
|
||||
return pbGet(2)
|
||||
when Settings::VAR_3_PLACEHOLDER_SPECIES
|
||||
return pbGet(3)
|
||||
end
|
||||
end
|
||||
|
||||
def generateRandomChampionSpecies(old_species)
|
||||
customsList = getCustomSpeciesList()
|
||||
bst_range = pbGet(VAR_RANDOMIZER_TRAINER_BST)
|
||||
new_species = $game_switches[SWITCH_RANDOM_GYM_CUSTOMS] ? getSpecies(getNewCustomSpecies(old_species, customsList, bst_range)) : getSpecies(getNewSpecies(old_species, bst_range))
|
||||
#every pokemon should be fully evolved
|
||||
evolved_species_id = getEvolution(new_species)
|
||||
evolved_species_id = getEvolution(evolved_species_id)
|
||||
evolved_species_id = getEvolution(evolved_species_id)
|
||||
evolved_species_id = getEvolution(evolved_species_id)
|
||||
return getSpecies(evolved_species_id)
|
||||
end
|
||||
|
||||
def generateRandomGymSpecies(old_species)
|
||||
gym_index = pbGet(VAR_CURRENT_GYM_TYPE)
|
||||
return old_species if gym_index == -1
|
||||
return generateRandomChampionSpecies(old_species) if gym_index == 999
|
||||
type_id = pbGet(VAR_GYM_TYPES_ARRAY)[gym_index]
|
||||
return old_species if type_id == -1
|
||||
|
||||
customsList = getCustomSpeciesList()
|
||||
bst_range = pbGet(VAR_RANDOMIZER_TRAINER_BST)
|
||||
gym_type = GameData::Type.get(type_id)
|
||||
while true
|
||||
new_species = $game_switches[SWITCH_RANDOM_GYM_CUSTOMS] ? getSpecies(getNewCustomSpecies(old_species, customsList, bst_range)) : getSpecies(getNewSpecies(old_species, bst_range))
|
||||
if new_species.hasType?(gym_type)
|
||||
return new_species
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def replace_species_to_randomized_gym(species, trainerId, pokemonIndex)
|
||||
if $PokemonGlobal.randomGymTrainersHash == nil
|
||||
$PokemonGlobal.randomGymTrainersHash = {}
|
||||
end
|
||||
if $game_switches[SWITCH_RANDOM_GYM_PERSIST_TEAMS] && $PokemonGlobal.randomGymTrainersHash != nil
|
||||
if $PokemonGlobal.randomGymTrainersHash[trainerId] != nil && $PokemonGlobal.randomGymTrainersHash[trainerId].length >= $PokemonGlobal.randomTrainersHash[trainerId].length
|
||||
return getSpecies($PokemonGlobal.randomGymTrainersHash[trainerId][pokemonIndex])
|
||||
end
|
||||
end
|
||||
new_species = generateRandomGymSpecies(species)
|
||||
if $game_switches[SWITCH_RANDOM_GYM_PERSIST_TEAMS]
|
||||
add_generated_species_to_gym_array(new_species, trainerId)
|
||||
end
|
||||
return new_species
|
||||
end
|
||||
|
||||
def add_generated_species_to_gym_array(new_species, trainerId)
|
||||
if (new_species.is_a?(Symbol))
|
||||
id = new_species
|
||||
else
|
||||
id = new_species.id_number
|
||||
end
|
||||
|
||||
expected_team_length = 1
|
||||
expected_team_length = $PokemonGlobal.randomTrainersHash[trainerId].length if $PokemonGlobal.randomTrainersHash[trainerId]
|
||||
new_team = []
|
||||
if $PokemonGlobal.randomGymTrainersHash[trainerId]
|
||||
new_team = $PokemonGlobal.randomGymTrainersHash[trainerId]
|
||||
end
|
||||
if new_team.length < expected_team_length
|
||||
new_team << id
|
||||
end
|
||||
$PokemonGlobal.randomGymTrainersHash[trainerId] = new_team
|
||||
end
|
||||
|
||||
def replace_species_to_randomized_regular(species, trainerId, pokemonIndex)
|
||||
if $PokemonGlobal.randomTrainersHash[trainerId] == nil
|
||||
Kernel.pbMessage(_INTL("The trainers need to be re-shuffled."))
|
||||
Kernel.pbShuffleTrainers()
|
||||
end
|
||||
new_species_dex = $PokemonGlobal.randomTrainersHash[trainerId][pokemonIndex]
|
||||
return getSpecies(new_species_dex)
|
||||
end
|
||||
|
||||
def isGymBattle
|
||||
return ($game_switches[SWITCH_RANDOM_TRAINERS] && ($game_variables[VAR_CURRENT_GYM_TYPE] != -1) || ($game_switches[SWITCH_FIRST_RIVAL_BATTLE] && $game_switches[SWITCH_RANDOM_STARTERS]))
|
||||
end
|
||||
|
||||
def replace_species_to_randomized(species, trainerId, pokemonIndex)
|
||||
return species if $game_switches[SWITCH_FIRST_RIVAL_BATTLE]
|
||||
return species if $game_switches[SWITCH_DONT_RANDOMIZE]
|
||||
if isGymBattle() && $game_switches[SWITCH_RANDOMIZE_GYMS_SEPARATELY]
|
||||
return replace_species_to_randomized_gym(species, trainerId, pokemonIndex)
|
||||
end
|
||||
return replace_species_to_randomized_regular(species, trainerId, pokemonIndex)
|
||||
|
||||
end
|
||||
|
||||
def replaceSingleSpeciesModeIfApplicable(species)
|
||||
if $game_switches[SWITCH_SINGLE_POKEMON_MODE]
|
||||
if $game_switches[SWITCH_SINGLE_POKEMON_MODE_HEAD]
|
||||
return replaceFusionsHeadWithSpecies(species)
|
||||
elsif $game_switches[SWITCH_SINGLE_POKEMON_MODE_BODY]
|
||||
return replaceFusionsBodyWithSpecies(species)
|
||||
elsif $game_switches[SWITCH_SINGLE_POKEMON_MODE_RANDOM]
|
||||
if (rand(2) == 0)
|
||||
return replaceFusionsHeadWithSpecies(species)
|
||||
else
|
||||
return replaceFusionsBodyWithSpecies(species)
|
||||
end
|
||||
end
|
||||
end
|
||||
return species
|
||||
end
|
||||
|
||||
def replaceFusionsHeadWithSpecies(species)
|
||||
speciesId = getDexNumberForSpecies(species)
|
||||
if speciesId > NB_POKEMON
|
||||
bodyPoke = getBodyID(speciesId)
|
||||
headPoke = pbGet(VAR_SINGLE_POKEMON_MODE)
|
||||
newSpecies = bodyPoke * NB_POKEMON + headPoke
|
||||
return getPokemon(newSpecies)
|
||||
end
|
||||
return species
|
||||
end
|
||||
|
||||
def replaceFusionsBodyWithSpecies(species)
|
||||
speciesId = getDexNumberForSpecies(species)
|
||||
if speciesId > NB_POKEMON
|
||||
bodyPoke = pbGet(VAR_SINGLE_POKEMON_MODE)
|
||||
headPoke = getHeadID(species)
|
||||
newSpecies = bodyPoke * NB_POKEMON + headPoke
|
||||
return getPokemon(newSpecies)
|
||||
end
|
||||
return species
|
||||
end
|
||||
|
||||
def to_trainer
|
||||
placeholder_species = [Settings::RIVAL_STARTER_PLACEHOLDER_SPECIES,
|
||||
Settings::VAR_1_PLACEHOLDER_SPECIES,
|
||||
Settings::VAR_2_PLACEHOLDER_SPECIES,
|
||||
Settings::VAR_3_PLACEHOLDER_SPECIES]
|
||||
# Determine trainer's name
|
||||
tr_name = self.name
|
||||
Settings::RIVAL_NAMES.each do |rival|
|
||||
next if rival[0] != @trainer_type || !$game_variables[rival[1]].is_a?(String)
|
||||
tr_name = $game_variables[rival[1]]
|
||||
break
|
||||
end
|
||||
# Create trainer object
|
||||
trainer = NPCTrainer.new(tr_name, @trainer_type)
|
||||
trainer.id = $Trainer.make_foreign_ID
|
||||
trainer.items = @items.clone
|
||||
trainer.lose_text = self.lose_text
|
||||
|
||||
isRematch = $game_switches[SWITCH_IS_REMATCH]
|
||||
isPlayingRandomized = $game_switches[SWITCH_RANDOM_TRAINERS] && !$game_switches[SWITCH_FIRST_RIVAL_BATTLE]
|
||||
rematchId = getRematchId(trainer.name, trainer.trainer_type)
|
||||
|
||||
# Create each Pokémon owned by the trainer
|
||||
index = 0
|
||||
@pokemon.each do |pkmn_data|
|
||||
#replace placeholder species infinite fusion edit
|
||||
species = GameData::Species.get(pkmn_data[:species]).species
|
||||
original_species = species
|
||||
if placeholder_species.include?(species)
|
||||
species = replace_species_with_placeholder(species)
|
||||
else
|
||||
species = replace_species_to_randomized(species, self.id, index) if isPlayingRandomized
|
||||
end
|
||||
species = replaceSingleSpeciesModeIfApplicable(species)
|
||||
if $game_switches[SWITCH_REVERSED_MODE]
|
||||
species = reverseFusionSpecies(species)
|
||||
end
|
||||
level = pkmn_data[:level]
|
||||
if $game_switches[SWITCH_GAME_DIFFICULTY_HARD]
|
||||
level = (level * Settings::HARD_MODE_LEVEL_MODIFIER).ceil
|
||||
if level > Settings::MAXIMUM_LEVEL
|
||||
level = Settings::MAXIMUM_LEVEL
|
||||
end
|
||||
end
|
||||
|
||||
if $game_switches[Settings::OVERRIDE_BATTLE_LEVEL_SWITCH]
|
||||
override_level = $game_variables[Settings::OVERRIDE_BATTLE_LEVEL_VALUE_VAR]
|
||||
if override_level.is_a?(Integer)
|
||||
level = override_level
|
||||
end
|
||||
end
|
||||
####
|
||||
|
||||
#trainer rematch infinite fusion edit
|
||||
if isRematch
|
||||
nbRematch = getNumberRematch(rematchId)
|
||||
level = getRematchLevel(level, nbRematch)
|
||||
species = evolveRematchPokemon(nbRematch, species)
|
||||
end
|
||||
|
||||
pkmn = Pokemon.new(species, level, trainer, false)
|
||||
|
||||
trainer.party.push(pkmn)
|
||||
# Set Pokémon's properties if defined
|
||||
if pkmn_data[:form]
|
||||
pkmn.forced_form = pkmn_data[:form] if MultipleForms.hasFunction?(species, "getForm")
|
||||
pkmn.form_simple = pkmn_data[:form]
|
||||
end
|
||||
|
||||
if $game_switches[SWITCH_RANDOM_HELD_ITEMS]
|
||||
pkmn.item = pbGetRandomHeldItem().id
|
||||
else
|
||||
pkmn.item = pkmn_data[:item]
|
||||
end
|
||||
if pkmn_data[:moves] && pkmn_data[:moves].length > 0 && original_species == species
|
||||
pkmn_data[:moves].each { |move| pkmn.learn_move(move) }
|
||||
else
|
||||
pkmn.reset_moves
|
||||
end
|
||||
pkmn.ability_index = pkmn_data[:ability_index]
|
||||
pkmn.ability = pkmn_data[:ability]
|
||||
pkmn.gender = pkmn_data[:gender] || ((trainer.male?) ? 0 : 1)
|
||||
pkmn.shiny = (pkmn_data[:shininess]) ? true : false
|
||||
if pkmn_data[:nature]
|
||||
pkmn.nature = pkmn_data[:nature]
|
||||
else
|
||||
nature = pkmn.species_data.id_number + GameData::TrainerType.get(trainer.trainer_type).id_number
|
||||
pkmn.nature = nature % (GameData::Nature::DATA.length / 2)
|
||||
end
|
||||
GameData::Stat.each_main do |s|
|
||||
if pkmn_data[:iv]
|
||||
pkmn.iv[s.id] = pkmn_data[:iv][s.id]
|
||||
else
|
||||
pkmn.iv[s.id] = [pkmn_data[:level] / 2, Pokemon::IV_STAT_LIMIT].min
|
||||
end
|
||||
if pkmn_data[:ev]
|
||||
pkmn.ev[s.id] = pkmn_data[:ev][s.id]
|
||||
else
|
||||
pkmn.ev[s.id] = [pkmn_data[:level] * 3 / 2, Pokemon::EV_LIMIT / 6].min
|
||||
end
|
||||
end
|
||||
pkmn.happiness = pkmn_data[:happiness] if pkmn_data[:happiness]
|
||||
pkmn.name = pkmn_data[:name] if pkmn_data[:name] && !pkmn_data[:name].empty?
|
||||
if pkmn_data[:shadowness]
|
||||
pkmn.makeShadow
|
||||
pkmn.update_shadow_moves(true)
|
||||
pkmn.shiny = false
|
||||
end
|
||||
pkmn.poke_ball = pkmn_data[:poke_ball] if pkmn_data[:poke_ball]
|
||||
pkmn.calc_stats
|
||||
|
||||
index += 1
|
||||
end
|
||||
return trainer
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
#===============================================================================
|
||||
# Deprecated methods
|
||||
#===============================================================================
|
||||
# @deprecated This alias is slated to be removed in v20.
|
||||
def pbGetTrainerData(tr_type, tr_name, tr_version = 0)
|
||||
Deprecation.warn_method('pbGetTrainerData', 'v20', 'GameData::Trainer.get(tr_type, tr_name, tr_version)')
|
||||
return GameData::Trainer.get(tr_type, tr_name, tr_version)
|
||||
end
|
||||
end
|
||||
@@ -2542,7 +2542,7 @@ end
|
||||
# class PokeBattle_Move_XXX < PokeBattle_Move
|
||||
# def pbMoveFailed?(user,targets)
|
||||
# if targets[0].effects[PBEffects::Transform]
|
||||
# @battle.pbDisplay(_INTL("But it failed!"))
|
||||
# @battle.pbDisplay("But it failed!")
|
||||
# return true
|
||||
# end
|
||||
# return false
|
||||
@@ -2552,7 +2552,7 @@ end
|
||||
# if target.effects[PBEffects::Transform] ||
|
||||
# target.effects[PBEffects::Illusion] ||
|
||||
# !target.pokemon.isFusion?
|
||||
# @battle.pbDisplay(_INTL("But it failed!"))
|
||||
# @battle.pbDisplay("But it failed!")
|
||||
# return true
|
||||
# end
|
||||
# return false
|
||||
|
||||
@@ -275,7 +275,7 @@ def pbHiddenPower(pkmn,forcedType=nil)
|
||||
if Settings::MECHANICS_GENERATION <= 5
|
||||
powerMin = 30
|
||||
powerMax = 70
|
||||
power |= (iv[:HP]&2)>>1
|
||||
power = (iv[:HP]&2)>>1
|
||||
power |= (iv[:ATTACK]&2)
|
||||
power |= (iv[:DEFENSE]&2)<<1
|
||||
power |= (iv[:SPEED]&2)<<2
|
||||
@@ -2995,7 +2995,7 @@ class PokeBattle_Move_0EB < PokeBattle_Move
|
||||
return true
|
||||
end
|
||||
# if @battle.wildBattle? && target.level>user.level
|
||||
# @battle.pbDisplay(_INTL("But it failed!"))
|
||||
# @battle.pbDisplay("But it failed!")
|
||||
# return true
|
||||
# end
|
||||
if @battle.trainerBattle?
|
||||
|
||||
@@ -70,7 +70,10 @@ module PokeBattle_BattleCommon
|
||||
# Record a Shadow Pokémon's species as having been caught
|
||||
pbPlayer.pokedex.set_shadow_pokemon_owned(pkmn.species) if pkmn.shadowPokemon?
|
||||
# Store caught Pokémon
|
||||
promptCaughtPokemonAction(pkmn)
|
||||
|
||||
gave_away_pokemon = promptGiveToPartner(pkmn) if isPartneredWithAnyTrainer()
|
||||
|
||||
promptCaughtPokemonAction(pkmn) if !gave_away_pokemon
|
||||
if $game_switches[AUTOSAVE_CATCH_SWITCH]
|
||||
Kernel.tryAutosave()
|
||||
end
|
||||
@@ -84,8 +87,8 @@ module PokeBattle_BattleCommon
|
||||
# return pbStorePokemon(pokemon) if !$Trainer.party_full?
|
||||
#
|
||||
# while !pickedOption
|
||||
# command = pbMessage(_INTL("\\ts[]Your team is full!"),
|
||||
# [_INTL("Add to your party"), _INTL("Store to PC"),], 2)
|
||||
# command = pbMessage("\\ts[]Your team is full!"),
|
||||
# ["Add to your party", "Store to PC",], 2)
|
||||
# echoln ("command " + command.to_s)
|
||||
# case command
|
||||
# when 0 #SWAP
|
||||
|
||||
@@ -99,7 +99,9 @@ class PokeBattle_Battle
|
||||
end
|
||||
@scene = scene
|
||||
@peer = PokeBattle_BattlePeer.create
|
||||
@battleAI = PokeBattle_AI.new(self)
|
||||
@battleAI = Settings::REMOTE_BATTLES_CONTROL ? RemotePokeBattle_AI.new(self) : PokeBattle_AI.new(self)
|
||||
#TODO
|
||||
|
||||
@field = PokeBattle_ActiveField.new # Whole field (gravity/rooms)
|
||||
@sides = [PokeBattle_ActiveSide.new, # Player's side
|
||||
PokeBattle_ActiveSide.new] # Foe's side
|
||||
|
||||
@@ -55,10 +55,10 @@ class PokeBattle_Battle
|
||||
requireds[idxTrainer] += 1
|
||||
end
|
||||
# Compare the have values with the need values
|
||||
if requireds.length>sideCounts.length
|
||||
raise _INTL("Error: def pbGetOwnerIndexFromBattlerIndex gives invalid owner index ({1} for battle type {2}v{3}, trainers {4}v{5})",
|
||||
requireds.length-1,@sideSizes[0],@sideSizes[1],side1counts.length,side2counts.length)
|
||||
end
|
||||
# if requireds.length>sideCounts.length
|
||||
# raise "Error: def pbGetOwnerIndexFromBattlerIndex gives invalid owner index ({1} for battle type {2}v{3}, trainers {4}v{5}",
|
||||
# requireds.length-1,@sideSizes[0],@sideSizes[1],side1counts.length,side2counts.length)
|
||||
# end
|
||||
sideCounts.each_with_index do |_count,i|
|
||||
if !requireds[i] || requireds[i]==0
|
||||
raise _INTL("Player-side trainer {1} has no battler position for their Pokémon to go (trying {2}v{3} battle)",
|
||||
|
||||
@@ -179,7 +179,7 @@ class PokeBattle_Battle
|
||||
dontAnimate = true
|
||||
# debugInfo = "Levels: #{curLevel}->#{newLevel} | Exp: #{pkmn.exp}->#{expFinal} | gain: #{expGained}"
|
||||
# raise RuntimeError.new(
|
||||
# echoln _INTL("{1}'s new level is less than its\r\ncurrent level, which shouldn't happen.\r\n[Debug: {2}]",
|
||||
# echoln "{1}'s new level is less than its\r\ncurrent level, which shouldn't happen.\r\n[Debug: {2}]",
|
||||
# pkmn.name, debugInfo)
|
||||
pbDisplayPaused(_INTL("{1}'s growth rate has changed to '{2}''. Its level will be adjusted to reflect its current exp.", pkmn.name, pkmn.growth_rate.real_name))
|
||||
end
|
||||
|
||||
@@ -74,7 +74,7 @@ class PokeBattle_Battle
|
||||
end
|
||||
# NOTE: Add your own Mega objects for particular NPC trainers here.
|
||||
# if pbGetOwnerFromBattlerIndex(idxBattler).trainer_type == :BUGCATCHER
|
||||
# return _INTL("Mega Net")
|
||||
# return "Mega Net"
|
||||
# end
|
||||
return _INTL("Mega Ring")
|
||||
end
|
||||
|
||||
@@ -57,13 +57,13 @@ class PokeBattle_Battle
|
||||
weather_data = GameData::BattleWeather.try_get(@field.weather)
|
||||
pbCommonAnimation(weather_data.animation) if weather_data
|
||||
case @field.weather
|
||||
# when :Sun then pbDisplay(_INTL("The sunlight is strong."))
|
||||
# when :Rain then pbDisplay(_INTL("Rain continues to fall."))
|
||||
# when :Sun then pbDisplay("The sunlight is strong.")
|
||||
# when :Rain then pbDisplay("Rain continues to fall.")
|
||||
when :Sandstorm then pbDisplay(_INTL("The sandstorm is raging."))
|
||||
when :Hail then pbDisplay(_INTL("The hail is crashing down."))
|
||||
# when :HarshSun then pbDisplay(_INTL("The sunlight is extremely harsh."))
|
||||
# when :HeavyRain then pbDisplay(_INTL("It is raining heavily."))
|
||||
# when :StrongWinds then pbDisplay(_INTL("The wind is strong."))
|
||||
# when :HarshSun then pbDisplay("The sunlight is extremely harsh.")
|
||||
# when :HeavyRain then pbDisplay("It is raining heavily.")
|
||||
# when :StrongWinds then pbDisplay("The wind is strong.")
|
||||
when :ShadowSky then pbDisplay(_INTL("The shadow sky continues."))
|
||||
end
|
||||
# Effects due to weather
|
||||
|
||||
@@ -8,11 +8,11 @@ class PokeBattle_AI
|
||||
return false if !item
|
||||
# Determine target of item (always the Pokémon choosing the action)
|
||||
useType = GameData::Item.get(item).battle_use
|
||||
if [1, 2, 3, 6, 7, 8].include?(useType) # Use on Pokémon
|
||||
idxTarget = @battle.battlers[idxTarget].pokemonIndex # Party Pokémon
|
||||
if [1, 2, 3, 6, 7, 8].include?(useType) # Use on Pokémon
|
||||
idxTarget = @battle.battlers[idxTarget].pokemonIndex # Party Pokémon
|
||||
end
|
||||
# Register use of item
|
||||
@battle.pbRegisterItem(idxBattler,item,idxTarget)
|
||||
@battle.pbRegisterItem(idxBattler, item, idxTarget)
|
||||
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) will use item #{GameData::Item.get(item).name}")
|
||||
return true
|
||||
end
|
||||
@@ -22,33 +22,33 @@ class PokeBattle_AI
|
||||
def pbEnemyItemToUse(idxBattler)
|
||||
return nil if !@battle.internalBattle
|
||||
items = @battle.pbGetOwnerItems(idxBattler)
|
||||
return nil if !items || items.length==0
|
||||
return nil if !items || items.length == 0
|
||||
# Determine target of item (always the Pokémon choosing the action)
|
||||
idxTarget = idxBattler # Battler using the item
|
||||
idxTarget = idxBattler # Battler using the item
|
||||
battler = @battle.battlers[idxTarget]
|
||||
pkmn = battler.pokemon
|
||||
# Item categories
|
||||
hpItems = {
|
||||
:POTION => 20,
|
||||
:SUPERPOTION => 50,
|
||||
:HYPERPOTION => 200,
|
||||
:MAXPOTION => 999,
|
||||
:BERRYJUICE => 20,
|
||||
:SWEETHEART => 20,
|
||||
:FRESHWATER => 50,
|
||||
:SODAPOP => 60,
|
||||
:LEMONADE => 80,
|
||||
:MOOMOOMILK => 100,
|
||||
:ORANBERRY => 10,
|
||||
:SITRUSBERRY => battler.totalhp/4,
|
||||
:ENERGYPOWDER => 50,
|
||||
:ENERGYROOT => 200
|
||||
:POTION => 20,
|
||||
:SUPERPOTION => 50,
|
||||
:HYPERPOTION => 200,
|
||||
:MAXPOTION => 999,
|
||||
:BERRYJUICE => 20,
|
||||
:SWEETHEART => 20,
|
||||
:FRESHWATER => 50,
|
||||
:SODAPOP => 60,
|
||||
:LEMONADE => 80,
|
||||
:MOOMOOMILK => 100,
|
||||
:ORANBERRY => 10,
|
||||
:SITRUSBERRY => battler.totalhp / 4,
|
||||
:ENERGYPOWDER => 50,
|
||||
:ENERGYROOT => 200
|
||||
}
|
||||
hpItems[:RAGECANDYBAR] = 20 if !Settings::RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS
|
||||
fullRestoreItems = [
|
||||
:FULLRESTORE
|
||||
:FULLRESTORE
|
||||
]
|
||||
oneStatusItems = [ # Preferred over items that heal all status problems
|
||||
oneStatusItems = [# Preferred over items that heal all status problems
|
||||
:AWAKENING, :CHESTOBERRY, :BLUEFLUTE,
|
||||
:ANTIDOTE, :PECHABERRY,
|
||||
:BURNHEAL, :RAWSTBERRY,
|
||||
@@ -56,112 +56,112 @@ class PokeBattle_AI
|
||||
:ICEHEAL, :ASPEARBERRY
|
||||
]
|
||||
allStatusItems = [
|
||||
:FULLHEAL, :LAVACOOKIE, :OLDGATEAU, :CASTELIACONE, :LUMIOSEGALETTE,
|
||||
:SHALOURSABLE, :BIGMALASADA, :LUMBERRY, :HEALPOWDER
|
||||
:FULLHEAL, :LAVACOOKIE, :OLDGATEAU, :CASTELIACONE, :LUMIOSEGALETTE,
|
||||
:SHALOURSABLE, :BIGMALASADA, :LUMBERRY, :HEALPOWDER
|
||||
]
|
||||
allStatusItems.push(:RAGECANDYBAR) if Settings::RAGE_CANDY_BAR_CURES_STATUS_PROBLEMS
|
||||
xItems = {
|
||||
:XATTACK => [:ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XATTACK2 => [:ATTACK, 2],
|
||||
:XATTACK3 => [:ATTACK, 3],
|
||||
:XATTACK6 => [:ATTACK, 6],
|
||||
:XDEFENSE => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XDEFENSE2 => [:DEFENSE, 2],
|
||||
:XDEFENSE3 => [:DEFENSE, 3],
|
||||
:XDEFENSE6 => [:DEFENSE, 6],
|
||||
:XDEFEND => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XDEFEND2 => [:DEFENSE, 2],
|
||||
:XDEFEND3 => [:DEFENSE, 3],
|
||||
:XDEFEND6 => [:DEFENSE, 6],
|
||||
:XSPATK => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPATK2 => [:SPECIAL_ATTACK, 2],
|
||||
:XSPATK3 => [:SPECIAL_ATTACK, 3],
|
||||
:XSPATK6 => [:SPECIAL_ATTACK, 6],
|
||||
:XSPECIAL => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPECIAL2 => [:SPECIAL_ATTACK, 2],
|
||||
:XSPECIAL3 => [:SPECIAL_ATTACK, 3],
|
||||
:XSPECIAL6 => [:SPECIAL_ATTACK, 6],
|
||||
:XSPDEF => [:SPECIAL_DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPDEF2 => [:SPECIAL_DEFENSE, 2],
|
||||
:XSPDEF3 => [:SPECIAL_DEFENSE, 3],
|
||||
:XSPDEF6 => [:SPECIAL_DEFENSE, 6],
|
||||
:XSPEED => [:SPEED, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPEED2 => [:SPEED, 2],
|
||||
:XSPEED3 => [:SPEED, 3],
|
||||
:XSPEED6 => [:SPEED, 6],
|
||||
:XACCURACY => [:ACCURACY, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XACCURACY2 => [:ACCURACY, 2],
|
||||
:XACCURACY3 => [:ACCURACY, 3],
|
||||
:XACCURACY6 => [:ACCURACY, 6]
|
||||
:XATTACK => [:ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XATTACK2 => [:ATTACK, 2],
|
||||
:XATTACK3 => [:ATTACK, 3],
|
||||
:XATTACK6 => [:ATTACK, 6],
|
||||
:XDEFENSE => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XDEFENSE2 => [:DEFENSE, 2],
|
||||
:XDEFENSE3 => [:DEFENSE, 3],
|
||||
:XDEFENSE6 => [:DEFENSE, 6],
|
||||
:XDEFEND => [:DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XDEFEND2 => [:DEFENSE, 2],
|
||||
:XDEFEND3 => [:DEFENSE, 3],
|
||||
:XDEFEND6 => [:DEFENSE, 6],
|
||||
:XSPATK => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPATK2 => [:SPECIAL_ATTACK, 2],
|
||||
:XSPATK3 => [:SPECIAL_ATTACK, 3],
|
||||
:XSPATK6 => [:SPECIAL_ATTACK, 6],
|
||||
:XSPECIAL => [:SPECIAL_ATTACK, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPECIAL2 => [:SPECIAL_ATTACK, 2],
|
||||
:XSPECIAL3 => [:SPECIAL_ATTACK, 3],
|
||||
:XSPECIAL6 => [:SPECIAL_ATTACK, 6],
|
||||
:XSPDEF => [:SPECIAL_DEFENSE, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPDEF2 => [:SPECIAL_DEFENSE, 2],
|
||||
:XSPDEF3 => [:SPECIAL_DEFENSE, 3],
|
||||
:XSPDEF6 => [:SPECIAL_DEFENSE, 6],
|
||||
:XSPEED => [:SPEED, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XSPEED2 => [:SPEED, 2],
|
||||
:XSPEED3 => [:SPEED, 3],
|
||||
:XSPEED6 => [:SPEED, 6],
|
||||
:XACCURACY => [:ACCURACY, (Settings::X_STAT_ITEMS_RAISE_BY_TWO_STAGES) ? 2 : 1],
|
||||
:XACCURACY2 => [:ACCURACY, 2],
|
||||
:XACCURACY3 => [:ACCURACY, 3],
|
||||
:XACCURACY6 => [:ACCURACY, 6]
|
||||
}
|
||||
# Determine lost HP
|
||||
losthp = battler.totalhp - battler.hp
|
||||
preferFullRestore = (battler.hp <= battler.totalhp * 2 / 3 &&
|
||||
(battler.status != :NONE || battler.effects[PBEffects::Confusion] > 0))
|
||||
|
||||
# Decide if Full Restore is actually preferred
|
||||
preferFullRestore = (battler.hp <= battler.totalhp / 2 &&
|
||||
(battler.status != :NONE || battler.effects[PBEffects::Confusion] > 0))
|
||||
|
||||
# Find all usable items
|
||||
usableHPItems = []
|
||||
usableHPItems = []
|
||||
usableStatusItems = []
|
||||
usableXItems = []
|
||||
usableXItems = []
|
||||
|
||||
items.each do |i|
|
||||
next if !i
|
||||
next if !@battle.pbCanUseItemOnPokemon?(i,pkmn,battler,@battle.scene,false)
|
||||
next if !ItemHandlers.triggerCanUseInBattle(i,pkmn,battler,nil,
|
||||
false,self,@battle.scene,false)
|
||||
# Log HP healing items
|
||||
if losthp > 0
|
||||
power = hpItems[i]
|
||||
if power
|
||||
usableHPItems.push([i, 5, power])
|
||||
next
|
||||
end
|
||||
next if !@battle.pbCanUseItemOnPokemon?(i, pkmn, battler, @battle.scene, false)
|
||||
next if !ItemHandlers.triggerCanUseInBattle(i, pkmn, battler, nil, false, self, @battle.scene, false)
|
||||
|
||||
itemQuantity = @battle.pbGetOwnerItems(idxBattler).count(i)
|
||||
|
||||
# Healing items (potions, berries, etc.)
|
||||
if hpItems[i] && losthp > 0
|
||||
priority = 5
|
||||
# Use lower priority if only 1 or 2 left
|
||||
priority += 3 if itemQuantity <= 2
|
||||
usableHPItems.push([i, priority, hpItems[i]])
|
||||
next
|
||||
end
|
||||
# Log Full Restores (HP healer and status curer)
|
||||
if losthp > 0 || battler.status != :NONE
|
||||
if fullRestoreItems.include?(i)
|
||||
usableHPItems.push([i, (preferFullRestore) ? 3 : 7, 999])
|
||||
usableStatusItems.push([i, (preferFullRestore) ? 3 : 9])
|
||||
next
|
||||
|
||||
# Full Restore items
|
||||
if fullRestoreItems.include?(i)
|
||||
if losthp >= battler.totalhp / 4 || battler.status != :NONE || battler.effects[PBEffects::Confusion] > 0
|
||||
# Only consider Full Restore if HP is below 25% or has status/confusion
|
||||
priority = preferFullRestore ? 3 : 7
|
||||
# Raise priority if stock is low to discourage waste
|
||||
priority += 5 if itemQuantity <= 2
|
||||
usableHPItems.push([i, priority, battler.totalhp])
|
||||
usableStatusItems.push([i, preferFullRestore ? 3 : 9])
|
||||
end
|
||||
next
|
||||
end
|
||||
# Log single status-curing items
|
||||
if oneStatusItems.include?(i)
|
||||
|
||||
# Single-status curers
|
||||
if oneStatusItems.include?(i) && battler.status != :NONE
|
||||
usableStatusItems.push([i, 5])
|
||||
next
|
||||
end
|
||||
# Log Full Heal-type items
|
||||
if allStatusItems.include?(i)
|
||||
|
||||
# Full heal-type items
|
||||
if allStatusItems.include?(i) && battler.status != :NONE
|
||||
usableStatusItems.push([i, 7])
|
||||
next
|
||||
end
|
||||
# Log stat-raising items
|
||||
|
||||
# Stat-raising items
|
||||
if xItems[i]
|
||||
data = xItems[i]
|
||||
usableXItems.push([i, battler.stages[data[0]], data[1]])
|
||||
next
|
||||
end
|
||||
end
|
||||
# Prioritise using a HP restoration item
|
||||
if usableHPItems.length>0 && (battler.hp<=battler.totalhp/4 ||
|
||||
(battler.hp<=battler.totalhp/2 && pbAIRandom(100)<30))
|
||||
usableHPItems.sort! { |a,b| (a[1]==b[1]) ? a[2]<=>b[2] : a[1]<=>b[1] }
|
||||
|
||||
# Prioritise using HP items (including Full Restore if really needed)
|
||||
if usableHPItems.length > 0 && (battler.hp <= battler.totalhp / 4 ||
|
||||
(battler.hp <= battler.totalhp / 2 && pbAIRandom(100) < 30))
|
||||
usableHPItems.sort! { |a, b| (a[1] == b[1]) ? a[2] <=> b[2] : a[1] <=> b[1] }
|
||||
prevItem = nil
|
||||
usableHPItems.each do |i|
|
||||
return i[0], idxTarget if i[2]>=losthp
|
||||
prevItem = i
|
||||
end
|
||||
return prevItem[0], idxTarget
|
||||
end
|
||||
# Next prioritise using a status-curing item
|
||||
if usableStatusItems.length>0 && pbAIRandom(100)<40
|
||||
usableStatusItems.sort! { |a,b| a[1]<=>b[1] }
|
||||
return usableStatusItems[0][0], idxTarget
|
||||
end
|
||||
# Next try using an X item
|
||||
if usableXItems.length>0 && pbAIRandom(100)<30
|
||||
usableXItems.sort! { |a,b| (a[1]==b[1]) ? a[2]<=>b[2] : a[1]<=>b[1] }
|
||||
prevItem = nil
|
||||
usableXItems.each do |i|
|
||||
break if prevItem && i[1]>prevItem[1]
|
||||
return i[0], idxTarget if i[1]+i[2]>=6
|
||||
return i[0], idxTarget if i[2] >= losthp
|
||||
prevItem = i
|
||||
end
|
||||
return prevItem[0], idxTarget
|
||||
|
||||
@@ -4,77 +4,77 @@ class PokeBattle_AI
|
||||
# chosen)
|
||||
#=============================================================================
|
||||
def pbChooseMoves(idxBattler)
|
||||
user = @battle.battlers[idxBattler]
|
||||
user = @battle.battlers[idxBattler]
|
||||
wildBattler = (@battle.wildBattle? && @battle.opposes?(idxBattler))
|
||||
skill = 0
|
||||
skill = 0
|
||||
if !wildBattler
|
||||
skill = @battle.pbGetOwnerFromBattlerIndex(user.index).skill_level || 0
|
||||
skill = @battle.pbGetOwnerFromBattlerIndex(user.index).skill_level || 0
|
||||
end
|
||||
# Get scores and targets for each move
|
||||
# NOTE: A move is only added to the choices array if it has a non-zero
|
||||
# score.
|
||||
choices = []
|
||||
user.eachMoveWithIndex do |_m,i|
|
||||
next if !@battle.pbCanChooseMove?(idxBattler,i,false)
|
||||
choices = []
|
||||
user.eachMoveWithIndex do |_m, i|
|
||||
next if !@battle.pbCanChooseMove?(idxBattler, i, false)
|
||||
if wildBattler
|
||||
pbRegisterMoveWild(user,i,choices)
|
||||
pbRegisterMoveWild(user, i, choices)
|
||||
else
|
||||
pbRegisterMoveTrainer(user,i,choices,skill)
|
||||
pbRegisterMoveTrainer(user, i, choices, skill)
|
||||
end
|
||||
end
|
||||
# Figure out useful information about the choices
|
||||
totalScore = 0
|
||||
maxScore = 0
|
||||
maxScore = 0
|
||||
choices.each do |c|
|
||||
totalScore += c[1]
|
||||
maxScore = c[1] if maxScore<c[1]
|
||||
maxScore = c[1] if maxScore < c[1]
|
||||
end
|
||||
# Log the available choices
|
||||
if $INTERNAL
|
||||
logMsg = "[AI] Move choices for #{user.pbThis(true)} (#{user.index}): "
|
||||
choices.each_with_index do |c,i|
|
||||
choices.each_with_index do |c, i|
|
||||
logMsg += "#{user.moves[c[0]].name}=#{c[1]}"
|
||||
logMsg += " (target #{c[2]})" if c[2]>=0
|
||||
logMsg += ", " if i<choices.length-1
|
||||
logMsg += " (target #{c[2]})" if c[2] >= 0
|
||||
logMsg += ", " if i < choices.length - 1
|
||||
end
|
||||
PBDebug.log(logMsg)
|
||||
end
|
||||
# Find any preferred moves and just choose from them
|
||||
if !wildBattler && skill>=PBTrainerAI.highSkill && maxScore>100
|
||||
if !wildBattler && skill >= PBTrainerAI.highSkill && maxScore > 100
|
||||
stDev = pbStdDev(choices)
|
||||
if stDev>=40 && pbAIRandom(100)<90
|
||||
if stDev >= 40 && pbAIRandom(100) < 90
|
||||
preferredMoves = []
|
||||
choices.each do |c|
|
||||
next if c[1]<200 && c[1]<maxScore*0.8
|
||||
next if c[1] < 200 && c[1] < maxScore * 0.8
|
||||
preferredMoves.push(c)
|
||||
preferredMoves.push(c) if c[1]==maxScore # Doubly prefer the best move
|
||||
preferredMoves.push(c) if c[1] == maxScore # Doubly prefer the best move
|
||||
end
|
||||
if preferredMoves.length>0
|
||||
if preferredMoves.length > 0
|
||||
m = preferredMoves[pbAIRandom(preferredMoves.length)]
|
||||
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) prefers #{user.moves[m[0]].name}")
|
||||
@battle.pbRegisterMove(idxBattler,m[0],false)
|
||||
@battle.pbRegisterTarget(idxBattler,m[2]) if m[2]>=0
|
||||
@battle.pbRegisterMove(idxBattler, m[0], false)
|
||||
@battle.pbRegisterTarget(idxBattler, m[2]) if m[2] >= 0
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
# Decide whether all choices are bad, and if so, try switching instead
|
||||
if !wildBattler && skill>=PBTrainerAI.highSkill
|
||||
if !wildBattler && skill >= PBTrainerAI.highSkill
|
||||
badMoves = false
|
||||
if (maxScore<=20 && user.turnCount>2) ||
|
||||
(maxScore<=40 && user.turnCount>5)
|
||||
badMoves = true if pbAIRandom(100)<80
|
||||
if (maxScore <= 20 && user.turnCount > 2) ||
|
||||
(maxScore <= 40 && user.turnCount > 5)
|
||||
badMoves = true if pbAIRandom(100) < 80
|
||||
end
|
||||
if !badMoves && totalScore<100 && user.turnCount>1
|
||||
if !badMoves && totalScore < 100 && user.turnCount > 1
|
||||
badMoves = true
|
||||
choices.each do |c|
|
||||
next if !user.moves[c[0]].damagingMove?
|
||||
badMoves = false
|
||||
break
|
||||
end
|
||||
badMoves = false if badMoves && pbAIRandom(100)<10
|
||||
badMoves = false if badMoves && pbAIRandom(100) < 10
|
||||
end
|
||||
if badMoves && pbEnemyShouldWithdrawEx?(idxBattler,true)
|
||||
if badMoves && pbEnemyShouldWithdrawEx?(idxBattler, true)
|
||||
if $INTERNAL
|
||||
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) will switch due to terrible moves")
|
||||
end
|
||||
@@ -82,13 +82,13 @@ class PokeBattle_AI
|
||||
end
|
||||
end
|
||||
# If there are no calculated choices, pick one at random
|
||||
if choices.length==0
|
||||
if choices.length == 0
|
||||
PBDebug.log("[AI] #{user.pbThis} (#{user.index}) doesn't want to use any moves; picking one at random")
|
||||
user.eachMoveWithIndex do |_m,i|
|
||||
next if !@battle.pbCanChooseMove?(idxBattler,i,false)
|
||||
choices.push([i,100,-1]) # Move index, score, target
|
||||
user.eachMoveWithIndex do |_m, i|
|
||||
next if !@battle.pbCanChooseMove?(idxBattler, i, false)
|
||||
choices.push([i, 100, -1]) # Move index, score, target
|
||||
end
|
||||
if choices.length==0 # No moves are physically possible to use; use Struggle
|
||||
if choices.length == 0 # No moves are physically possible to use; use Struggle
|
||||
@battle.pbAutoChooseMove(user.index)
|
||||
end
|
||||
end
|
||||
@@ -96,9 +96,9 @@ class PokeBattle_AI
|
||||
randNum = pbAIRandom(totalScore)
|
||||
choices.each do |c|
|
||||
randNum -= c[1]
|
||||
next if randNum>=0
|
||||
@battle.pbRegisterMove(idxBattler,c[0],false)
|
||||
@battle.pbRegisterTarget(idxBattler,c[2]) if c[2]>=0
|
||||
next if randNum >= 0
|
||||
@battle.pbRegisterMove(idxBattler, c[0], false)
|
||||
@battle.pbRegisterTarget(idxBattler, c[2]) if c[2] >= 0
|
||||
break
|
||||
end
|
||||
# Log the result
|
||||
@@ -111,40 +111,40 @@ class PokeBattle_AI
|
||||
# Get scores for the given move against each possible target
|
||||
#=============================================================================
|
||||
# Wild Pokémon choose their moves randomly.
|
||||
def pbRegisterMoveWild(_user,idxMove,choices)
|
||||
choices.push([idxMove,100,-1]) # Move index, score, target
|
||||
def pbRegisterMoveWild(_user, idxMove, choices)
|
||||
choices.push([idxMove, 100, -1]) # Move index, score, target
|
||||
end
|
||||
|
||||
# Trainer Pokémon calculate how much they want to use each of their moves.
|
||||
def pbRegisterMoveTrainer(user,idxMove,choices,skill)
|
||||
def pbRegisterMoveTrainer(user, idxMove, choices, skill)
|
||||
move = user.moves[idxMove]
|
||||
target_data = move.pbTarget(user)
|
||||
if target_data.num_targets > 1
|
||||
# If move affects multiple battlers and you don't choose a particular one
|
||||
totalScore = 0
|
||||
@battle.eachBattler do |b|
|
||||
next if !@battle.pbMoveCanTarget?(user.index,b.index,target_data)
|
||||
score = pbGetMoveScore(move,user,b,skill)
|
||||
next if !@battle.pbMoveCanTarget?(user.index, b.index, target_data)
|
||||
score = pbGetMoveScore(move, user, b, skill)
|
||||
totalScore += ((user.opposes?(b)) ? score : -score)
|
||||
end
|
||||
choices.push([idxMove,totalScore,-1]) if totalScore>0
|
||||
choices.push([idxMove, totalScore, -1]) if totalScore > 0
|
||||
elsif target_data.num_targets == 0
|
||||
# If move has no targets, affects the user, a side or the whole field
|
||||
score = pbGetMoveScore(move,user,user,skill)
|
||||
choices.push([idxMove,score,-1]) if score>0
|
||||
score = pbGetMoveScore(move, user, user, skill)
|
||||
choices.push([idxMove, score, -1]) if score > 0
|
||||
else
|
||||
# If move affects one battler and you have to choose which one
|
||||
scoresAndTargets = []
|
||||
@battle.eachBattler do |b|
|
||||
next if !@battle.pbMoveCanTarget?(user.index,b.index,target_data)
|
||||
next if !@battle.pbMoveCanTarget?(user.index, b.index, target_data)
|
||||
next if target_data.targets_foe && !user.opposes?(b)
|
||||
score = pbGetMoveScore(move,user,b,skill)
|
||||
scoresAndTargets.push([score,b.index]) if score>0
|
||||
score = pbGetMoveScore(move, user, b, skill)
|
||||
scoresAndTargets.push([score, b.index]) if score > 0
|
||||
end
|
||||
if scoresAndTargets.length>0
|
||||
if scoresAndTargets.length > 0
|
||||
# Get the one best target for the move
|
||||
scoresAndTargets.sort! { |a,b| b[0]<=>a[0] }
|
||||
choices.push([idxMove,scoresAndTargets[0][0],scoresAndTargets[0][1]])
|
||||
scoresAndTargets.sort! { |a, b| b[0] <=> a[0] }
|
||||
choices.push([idxMove, scoresAndTargets[0][0], scoresAndTargets[0][1]])
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -152,38 +152,38 @@ class PokeBattle_AI
|
||||
#=============================================================================
|
||||
# Get a score for the given move being used against the given target
|
||||
#=============================================================================
|
||||
def pbGetMoveScore(move,user,target,skill=100)
|
||||
skill = PBTrainerAI.minimumSkill if skill<PBTrainerAI.minimumSkill
|
||||
def pbGetMoveScore(move, user, target, skill = 100)
|
||||
skill = PBTrainerAI.minimumSkill if skill < PBTrainerAI.minimumSkill
|
||||
score = 100
|
||||
score = pbGetMoveScoreFunctionCode(score,move,user,target,skill)
|
||||
score = pbGetMoveScoreFunctionCode(score, move, user, target, skill)
|
||||
# A score of 0 here means it absolutely should not be used
|
||||
return 0 if score<=0
|
||||
if skill>=PBTrainerAI.mediumSkill
|
||||
return 0 if score <= 0
|
||||
if skill >= PBTrainerAI.mediumSkill
|
||||
# Prefer damaging moves if AI has no more Pokémon or AI is less clever
|
||||
if @battle.pbAbleNonActiveCount(user.idxOwnSide)==0
|
||||
if !(skill>=PBTrainerAI.highSkill && @battle.pbAbleNonActiveCount(target.idxOwnSide)>0)
|
||||
if @battle.pbAbleNonActiveCount(user.idxOwnSide) == 0
|
||||
if !(skill >= PBTrainerAI.highSkill && @battle.pbAbleNonActiveCount(target.idxOwnSide) > 0)
|
||||
if move.statusMove?
|
||||
score /= 1.5
|
||||
elsif target.hp<=target.totalhp/2
|
||||
elsif target.hp <= target.totalhp / 2
|
||||
score *= 1.5
|
||||
end
|
||||
end
|
||||
end
|
||||
# Don't prefer attacking the target if they'd be semi-invulnerable
|
||||
if skill>=PBTrainerAI.highSkill && move.accuracy>0 &&
|
||||
(target.semiInvulnerable? || target.effects[PBEffects::SkyDrop]>=0)
|
||||
if skill >= PBTrainerAI.highSkill && move.accuracy > 0 &&
|
||||
(target.semiInvulnerable? || target.effects[PBEffects::SkyDrop] >= 0)
|
||||
miss = true
|
||||
miss = false if user.hasActiveAbility?(:NOGUARD) || target.hasActiveAbility?(:NOGUARD)
|
||||
if miss && pbRoughStat(user,:SPEED,skill)>pbRoughStat(target,:SPEED,skill)
|
||||
if miss && pbRoughStat(user, :SPEED, skill) > pbRoughStat(target, :SPEED, skill)
|
||||
# Knows what can get past semi-invulnerability
|
||||
if target.effects[PBEffects::SkyDrop]>=0
|
||||
if target.effects[PBEffects::SkyDrop] >= 0
|
||||
miss = false if move.hitsFlyingTargets?
|
||||
else
|
||||
if target.inTwoTurnAttack?("0C9","0CC","0CE") # Fly, Bounce, Sky Drop
|
||||
if target.inTwoTurnAttack?("0C9", "0CC", "0CE") # Fly, Bounce, Sky Drop
|
||||
miss = false if move.hitsFlyingTargets?
|
||||
elsif target.inTwoTurnAttack?("0CA") # Dig
|
||||
elsif target.inTwoTurnAttack?("0CA") # Dig
|
||||
miss = false if move.hitsDiggingTargets?
|
||||
elsif target.inTwoTurnAttack?("0CB") # Dive
|
||||
elsif target.inTwoTurnAttack?("0CB") # Dive
|
||||
miss = false if move.hitsDivingTargets?
|
||||
end
|
||||
end
|
||||
@@ -191,11 +191,15 @@ class PokeBattle_AI
|
||||
score -= 80 if miss
|
||||
end
|
||||
# Pick a good move for the Choice items
|
||||
if user.hasActiveItem?([:CHOICEBAND,:CHOICESPECS,:CHOICESCARF])
|
||||
if move.baseDamage>=60; score += 60
|
||||
elsif move.damagingMove?; score += 30
|
||||
elsif move.function=="0F2"; score += 70 # Trick
|
||||
else; score -= 60
|
||||
if user.hasActiveItem?([:CHOICEBAND, :CHOICESPECS, :CHOICESCARF])
|
||||
if move.baseDamage >= 60;
|
||||
score += 60
|
||||
elsif move.damagingMove?;
|
||||
score += 30
|
||||
elsif move.function == "0F2";
|
||||
score += 70 # Trick
|
||||
else
|
||||
; score -= 60
|
||||
end
|
||||
end
|
||||
# If user is asleep, prefer moves that are usable while asleep
|
||||
@@ -229,17 +233,18 @@ class PokeBattle_AI
|
||||
end
|
||||
# Adjust score based on how much damage it can deal
|
||||
if move.damagingMove?
|
||||
score = pbGetMoveScoreDamage(score,move,user,target,skill)
|
||||
else # Status moves
|
||||
score = pbGetMoveScoreDamage(score, move, user, target, skill)
|
||||
else
|
||||
# Status moves
|
||||
# Don't prefer attacks which don't deal damage
|
||||
score -= 10
|
||||
# Account for accuracy of move
|
||||
accuracy = pbRoughAccuracy(move,user,target,skill)
|
||||
score *= accuracy/100.0
|
||||
score = 0 if score<=10 && skill>=PBTrainerAI.highSkill
|
||||
accuracy = pbRoughAccuracy(move, user, target, skill)
|
||||
score *= accuracy / 100.0
|
||||
score = 0 if score <= 10 && skill >= PBTrainerAI.highSkill
|
||||
end
|
||||
score = score.to_i
|
||||
score = 0 if score<0
|
||||
score = 0 if score < 0
|
||||
return score
|
||||
end
|
||||
|
||||
@@ -247,27 +252,27 @@ class PokeBattle_AI
|
||||
# Add to a move's score based on how much damage it will deal (as a percentage
|
||||
# of the target's current HP)
|
||||
#=============================================================================
|
||||
def pbGetMoveScoreDamage(score,move,user,target,skill)
|
||||
def pbGetMoveScoreDamage(score, move, user, target, skill)
|
||||
# Don't prefer moves that are ineffective because of abilities or effects
|
||||
return 0 if score<=0 || pbCheckMoveImmunity(score,move,user,target,skill)
|
||||
return 0 if score <= 0 || pbCheckMoveImmunity(score, move, user, target, skill)
|
||||
# Calculate how much damage the move will do (roughly)
|
||||
baseDmg = pbMoveBaseDamage(move,user,target,skill)
|
||||
realDamage = pbRoughDamage(move,user,target,skill,baseDmg)
|
||||
baseDmg = pbMoveBaseDamage(move, user, target, skill)
|
||||
realDamage = pbRoughDamage(move, user, target, skill, baseDmg)
|
||||
# Account for accuracy of move
|
||||
accuracy = pbRoughAccuracy(move,user,target,skill)
|
||||
realDamage *= accuracy/100.0
|
||||
accuracy = pbRoughAccuracy(move, user, target, skill)
|
||||
realDamage *= accuracy / 100.0
|
||||
# Two-turn attacks waste 2 turns to deal one lot of damage
|
||||
if move.chargingTurnMove? || move.function=="0C2" # Hyper Beam
|
||||
realDamage *= 2/3 # Not halved because semi-invulnerable during use or hits first turn
|
||||
if move.chargingTurnMove? || move.function == "0C2" # Hyper Beam
|
||||
realDamage *= 2 / 3 # Not halved because semi-invulnerable during use or hits first turn
|
||||
end
|
||||
# Prefer flinching external effects (note that move effects which cause
|
||||
# flinching are dealt with in the function code part of score calculation)
|
||||
if skill>=PBTrainerAI.mediumSkill
|
||||
if skill >= PBTrainerAI.mediumSkill
|
||||
if !target.hasActiveAbility?(:INNERFOCUS) &&
|
||||
!target.hasActiveAbility?(:SHIELDDUST) &&
|
||||
target.effects[PBEffects::Substitute]==0
|
||||
!target.hasActiveAbility?(:SHIELDDUST) &&
|
||||
target.effects[PBEffects::Substitute] == 0
|
||||
canFlinch = false
|
||||
if move.canKingsRock? && user.hasActiveItem?([:KINGSROCK,:RAZORFANG])
|
||||
if move.canKingsRock? && user.hasActiveItem?([:KINGSROCK, :RAZORFANG])
|
||||
canFlinch = true
|
||||
end
|
||||
if user.hasActiveAbility?(:STENCH) && !move.flinchingMove?
|
||||
@@ -277,14 +282,14 @@ class PokeBattle_AI
|
||||
end
|
||||
end
|
||||
# Convert damage to percentage of target's remaining HP
|
||||
damagePercentage = realDamage*100.0/target.hp
|
||||
damagePercentage = realDamage * 100.0 / target.hp
|
||||
# Don't prefer weak attacks
|
||||
# damagePercentage /= 2 if damagePercentage<20
|
||||
# damagePercentage /= 2 if damagePercentage<20
|
||||
# Prefer damaging attack if level difference is significantly high
|
||||
damagePercentage *= 1.2 if user.level-10>target.level
|
||||
damagePercentage *= 1.2 if user.level - 10 > target.level
|
||||
# Adjust score
|
||||
damagePercentage = 120 if damagePercentage>120 # Treat all lethal moves the same
|
||||
damagePercentage += 40 if damagePercentage>100 # Prefer moves likely to be lethal
|
||||
damagePercentage = 120 if damagePercentage > 120 # Treat all lethal moves the same
|
||||
damagePercentage += 40 if damagePercentage > 100 # Prefer moves likely to be lethal
|
||||
score += damagePercentage.to_i
|
||||
return score
|
||||
end
|
||||
|
||||
@@ -177,7 +177,8 @@ BallHandlers::ModifyCatchRate.add(:LEVELBALL,proc { |ball,catchRate,battle,battl
|
||||
|
||||
BallHandlers::ModifyCatchRate.add(:LUREBALL,proc { |ball,catchRate,battle,battler,ultraBeast|
|
||||
multiplier = (Settings::NEW_POKE_BALL_CATCH_RATES) ? 5 : 3
|
||||
catchRate *= multiplier if GameData::EncounterType.get($PokemonTemp.encounterType).type == :fishing
|
||||
encounterType = GameData::EncounterType.try_get($PokemonTemp.encounterType)
|
||||
catchRate *= multiplier if encounterType.is_a?(GameData::EncounterType) && encounterType.type == :fishing
|
||||
next [catchRate,255].min
|
||||
})
|
||||
|
||||
|
||||
@@ -93,9 +93,9 @@ class PokemonDataBox < SpriteWrapper
|
||||
|
||||
def initializeOtherGraphics(viewport)
|
||||
# Create other bitmaps
|
||||
@numbersBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/icon_numbers"))
|
||||
@hpBarBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/overlay_hp"))
|
||||
@expBarBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/overlay_exp"))
|
||||
@numbersBitmap = AnimatedBitmap.new("Graphics/Pictures/Battle/icon_numbers")
|
||||
@hpBarBitmap = AnimatedBitmap.new("Graphics/Pictures/Battle/overlay_hp")
|
||||
@expBarBitmap = AnimatedBitmap.new("Graphics/Pictures/Battle/overlay_exp")
|
||||
# Create sprite to draw HP numbers on
|
||||
@hpNumbers = BitmapSprite.new(124,16,viewport)
|
||||
pbSetSmallFont(@hpNumbers.bitmap)
|
||||
@@ -235,9 +235,9 @@ class PokemonDataBox < SpriteWrapper
|
||||
# Draw Pokémon's gender symbol
|
||||
case @battler.displayGender
|
||||
when 0 # Male
|
||||
textPos.push([_INTL("♂"),@spriteBaseX+126,0,false,MALE_BASE_COLOR,MALE_SHADOW_COLOR])
|
||||
textPos.push(["♂",@spriteBaseX+126,0,false,MALE_BASE_COLOR,MALE_SHADOW_COLOR])
|
||||
when 1 # Female
|
||||
textPos.push([_INTL("♀"),@spriteBaseX+126,0,false,FEMALE_BASE_COLOR,FEMALE_SHADOW_COLOR])
|
||||
textPos.push(["♀",@spriteBaseX+126,0,false,FEMALE_BASE_COLOR,FEMALE_SHADOW_COLOR])
|
||||
end
|
||||
pbDrawTextPositions(self.bitmap,textPos)
|
||||
# Draw Pokémon's level
|
||||
@@ -450,7 +450,7 @@ class AbilitySplashBar < SpriteWrapper
|
||||
@side = side
|
||||
@battler = nil
|
||||
# Create sprite wrapper that displays background graphic
|
||||
@bgBitmap = AnimatedBitmap.new(_INTL("Graphics/Pictures/Battle/ability_bar"))
|
||||
@bgBitmap = AnimatedBitmap.new("Graphics/Pictures/Battle/ability_bar")
|
||||
@bgSprite = SpriteWrapper.new(viewport)
|
||||
@bgSprite.bitmap = @bgBitmap.bitmap
|
||||
@bgSprite.src_rect.y = (side==0) ? 0 : @bgBitmap.height/2
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user