mirror of
https://github.com/infinitefusion/infinitefusion-e18.git
synced 2025-12-06 06:01:46 +00:00
Rearranged OrgBattle scripts
This commit is contained in:
@@ -14,7 +14,7 @@ class Game_Character
|
|||||||
attr_accessor :character_hue
|
attr_accessor :character_hue
|
||||||
attr_reader :opacity
|
attr_reader :opacity
|
||||||
attr_reader :blend_type
|
attr_reader :blend_type
|
||||||
attr_reader :direction
|
attr_accessor :direction
|
||||||
attr_accessor :pattern
|
attr_accessor :pattern
|
||||||
attr_accessor :pattern_surf
|
attr_accessor :pattern_surf
|
||||||
attr_accessor :lock_pattern
|
attr_accessor :lock_pattern
|
||||||
|
|||||||
@@ -0,0 +1,425 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleChallenge
|
||||||
|
attr_reader :currentChallenge
|
||||||
|
|
||||||
|
BattleTowerID = 0
|
||||||
|
BattlePalaceID = 1
|
||||||
|
BattleArenaID = 2
|
||||||
|
BattleFactoryID = 3
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@bc = BattleChallengeData.new
|
||||||
|
@currentChallenge = -1
|
||||||
|
@types = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def set(id, numrounds, rules)
|
||||||
|
@id = id
|
||||||
|
@numRounds = numrounds
|
||||||
|
@rules = rules
|
||||||
|
pbWriteCup(id, rules)
|
||||||
|
end
|
||||||
|
|
||||||
|
def register(id, doublebattle, numrounds, numPokemon, battletype, mode = 1)
|
||||||
|
ensureType(id)
|
||||||
|
if battletype == BattleFactoryID
|
||||||
|
@bc.setExtraData(BattleFactoryData.new(@bc))
|
||||||
|
numPokemon = 3
|
||||||
|
battletype = BattleTowerID
|
||||||
|
end
|
||||||
|
@numRounds = numrounds
|
||||||
|
@rules = modeToRules(doublebattle, numPokemon, battletype, mode)
|
||||||
|
end
|
||||||
|
|
||||||
|
def rules
|
||||||
|
if !@rules
|
||||||
|
@rules = modeToRules(self.data.doublebattle, self.data.numPokemon,
|
||||||
|
self.data.battletype, self.data.mode)
|
||||||
|
end
|
||||||
|
return @rules
|
||||||
|
end
|
||||||
|
|
||||||
|
def modeToRules(doublebattle, numPokemon, battletype, mode)
|
||||||
|
rules = PokemonChallengeRules.new
|
||||||
|
# Set the battle type
|
||||||
|
case battletype
|
||||||
|
when BattlePalaceID
|
||||||
|
rules.setBattleType(BattlePalace.new)
|
||||||
|
when BattleArenaID
|
||||||
|
rules.setBattleType(BattleArena.new)
|
||||||
|
doublebattle = false
|
||||||
|
else # Factory works the same as Tower
|
||||||
|
rules.setBattleType(BattleTower.new)
|
||||||
|
end
|
||||||
|
# Set standard rules and maximum level
|
||||||
|
case mode
|
||||||
|
when 1 # Open Level
|
||||||
|
rules.setRuleset(StandardRules.new(numPokemon, GameData::GrowthRate.max_level))
|
||||||
|
rules.setLevelAdjustment(OpenLevelAdjustment.new(30))
|
||||||
|
when 2 # Battle Tent
|
||||||
|
rules.setRuleset(StandardRules.new(numPokemon, GameData::GrowthRate.max_level))
|
||||||
|
rules.setLevelAdjustment(OpenLevelAdjustment.new(60))
|
||||||
|
else
|
||||||
|
rules.setRuleset(StandardRules.new(numPokemon, 50))
|
||||||
|
rules.setLevelAdjustment(OpenLevelAdjustment.new(50))
|
||||||
|
end
|
||||||
|
# Set whether battles are single or double
|
||||||
|
if doublebattle
|
||||||
|
rules.addBattleRule(DoubleBattle.new)
|
||||||
|
else
|
||||||
|
rules.addBattleRule(SingleBattle.new)
|
||||||
|
end
|
||||||
|
return rules
|
||||||
|
end
|
||||||
|
|
||||||
|
def start(*args)
|
||||||
|
t = ensureType(@id)
|
||||||
|
@currentChallenge = @id # must appear before pbStart
|
||||||
|
@bc.pbStart(t, @numRounds)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbStart(challenge)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbEnd
|
||||||
|
if @currentChallenge != -1
|
||||||
|
ensureType(@currentChallenge).saveWins(@bc)
|
||||||
|
@currentChallenge = -1
|
||||||
|
end
|
||||||
|
@bc.pbEnd
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattle
|
||||||
|
return @bc.extraData.pbBattle(self) if @bc.extraData # Battle Factory
|
||||||
|
opponent = pbGenerateBattleTrainer(self.nextTrainer, self.rules)
|
||||||
|
bttrainers = pbGetBTTrainers(@id)
|
||||||
|
trainerdata = bttrainers[self.nextTrainer]
|
||||||
|
ret = pbOrganizedBattleEx(opponent,self.rules,
|
||||||
|
pbGetMessageFromHash(MessageTypes::EndSpeechLose, trainerdata[4]),
|
||||||
|
pbGetMessageFromHash(MessageTypes::EndSpeechWin, trainerdata[3]))
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbInChallenge?
|
||||||
|
return pbInProgress?
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbInProgress?
|
||||||
|
return @bc.inProgress
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbResting?
|
||||||
|
return @bc.resting
|
||||||
|
end
|
||||||
|
|
||||||
|
def extra; @bc.extraData; end
|
||||||
|
def decision; @bc.decision; end
|
||||||
|
def wins; @bc.wins; end
|
||||||
|
def swaps; @bc.swaps; end
|
||||||
|
def battleNumber; @bc.battleNumber; end
|
||||||
|
def nextTrainer; @bc.nextTrainer; end
|
||||||
|
def pbGoOn; @bc.pbGoOn; end
|
||||||
|
def pbAddWin; @bc.pbAddWin; end
|
||||||
|
def pbCancel; @bc.pbCancel; end
|
||||||
|
def pbRest; @bc.pbRest; end
|
||||||
|
def pbMatchOver?; @bc.pbMatchOver?; end
|
||||||
|
def pbGoToStart; @bc.pbGoToStart; end
|
||||||
|
|
||||||
|
def setDecision(value)
|
||||||
|
@bc.decision = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def setParty(value)
|
||||||
|
@bc.setParty(value)
|
||||||
|
end
|
||||||
|
|
||||||
|
def data
|
||||||
|
return nil if !pbInProgress? || @currentChallenge < 0
|
||||||
|
return ensureType(@currentChallenge).clone
|
||||||
|
end
|
||||||
|
|
||||||
|
def getCurrentWins(challenge)
|
||||||
|
return ensureType(challenge).currentWins
|
||||||
|
end
|
||||||
|
|
||||||
|
def getPreviousWins(challenge)
|
||||||
|
return ensureType(challenge).previousWins
|
||||||
|
end
|
||||||
|
|
||||||
|
def getMaxWins(challenge)
|
||||||
|
return ensureType(challenge).maxWins
|
||||||
|
end
|
||||||
|
|
||||||
|
def getCurrentSwaps(challenge)
|
||||||
|
return ensureType(challenge).currentSwaps
|
||||||
|
end
|
||||||
|
|
||||||
|
def getPreviousSwaps(challenge)
|
||||||
|
return ensureType(challenge).previousSwaps
|
||||||
|
end
|
||||||
|
|
||||||
|
def getMaxSwaps(challenge)
|
||||||
|
return ensureType(challenge).maxSwaps
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def ensureType(id)
|
||||||
|
@types[id] = BattleChallengeType.new if !@types[id]
|
||||||
|
return @types[id]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleChallengeData
|
||||||
|
attr_reader :battleNumber
|
||||||
|
attr_reader :numRounds
|
||||||
|
attr_reader :party
|
||||||
|
attr_reader :inProgress
|
||||||
|
attr_reader :resting
|
||||||
|
attr_reader :wins
|
||||||
|
attr_reader :swaps
|
||||||
|
attr_accessor :decision
|
||||||
|
attr_reader :extraData
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
reset
|
||||||
|
end
|
||||||
|
|
||||||
|
def setExtraData(value)
|
||||||
|
@extraData = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def setParty(value)
|
||||||
|
if @inProgress
|
||||||
|
$Trainer.party = value
|
||||||
|
@party = value
|
||||||
|
else
|
||||||
|
@party = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbStart(t, numRounds)
|
||||||
|
@inProgress = true
|
||||||
|
@resting = false
|
||||||
|
@decision = 0
|
||||||
|
@swaps = t.currentSwaps
|
||||||
|
@wins = t.currentWins
|
||||||
|
@battleNumber = 1
|
||||||
|
@trainers = []
|
||||||
|
raise _INTL("Number of rounds is 0 or less.") if numRounds <= 0
|
||||||
|
@numRounds = numRounds
|
||||||
|
# Get all the trainers for the next set of battles
|
||||||
|
btTrainers = pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
||||||
|
while @trainers.length < @numRounds
|
||||||
|
newtrainer = pbBattleChallengeTrainer(@wins + @trainers.length, btTrainers)
|
||||||
|
found = false
|
||||||
|
for tr in @trainers
|
||||||
|
found = true if tr == newtrainer
|
||||||
|
end
|
||||||
|
@trainers.push(newtrainer) if !found
|
||||||
|
end
|
||||||
|
@start = [$game_map.map_id, $game_player.x, $game_player.y]
|
||||||
|
@oldParty = $Trainer.party
|
||||||
|
$Trainer.party = @party if @party
|
||||||
|
Game.save(safe: true)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbGoToStart
|
||||||
|
if $scene.is_a?(Scene_Map)
|
||||||
|
$game_temp.player_transferring = true
|
||||||
|
$game_temp.player_new_map_id = @start[0]
|
||||||
|
$game_temp.player_new_x = @start[1]
|
||||||
|
$game_temp.player_new_y = @start[2]
|
||||||
|
$game_temp.player_new_direction = 8
|
||||||
|
$scene.transfer_player
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbAddWin
|
||||||
|
return if !@inProgress
|
||||||
|
@battleNumber += 1
|
||||||
|
@wins += 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbAddSwap
|
||||||
|
@swaps += 1 if @inProgress
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbMatchOver?
|
||||||
|
return true if !@inProgress || @decision != 0
|
||||||
|
return @battleNumber > @numRounds
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbRest
|
||||||
|
return if !@inProgress
|
||||||
|
@resting = true
|
||||||
|
pbSaveInProgress
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbGoOn
|
||||||
|
return if !@inProgress
|
||||||
|
@resting = false
|
||||||
|
pbSaveInProgress
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbCancel
|
||||||
|
$Trainer.party = @oldParty if @oldParty
|
||||||
|
reset
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbEnd
|
||||||
|
$Trainer.party = @oldParty
|
||||||
|
return if !@inProgress
|
||||||
|
save = (@decision != 0)
|
||||||
|
reset
|
||||||
|
$game_map.need_refresh = true
|
||||||
|
Game.save(safe: true) if save
|
||||||
|
end
|
||||||
|
|
||||||
|
def nextTrainer
|
||||||
|
return @trainers[@battleNumber - 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def reset
|
||||||
|
@inProgress = false
|
||||||
|
@resting = false
|
||||||
|
@start = nil
|
||||||
|
@decision = 0
|
||||||
|
@wins = 0
|
||||||
|
@swaps = 0
|
||||||
|
@battleNumber = 0
|
||||||
|
@trainers = []
|
||||||
|
@oldParty = nil
|
||||||
|
@party = nil
|
||||||
|
@extraData = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbSaveInProgress
|
||||||
|
oldmapid = $game_map.map_id
|
||||||
|
oldx = $game_player.x
|
||||||
|
oldy = $game_player.y
|
||||||
|
olddirection = $game_player.direction
|
||||||
|
$game_map.map_id = @start[0]
|
||||||
|
$game_player.moveto2(@start[1], @start[2])
|
||||||
|
$game_player.direction = 8 # facing up
|
||||||
|
Game.save(safe: true)
|
||||||
|
$game_map.map_id = oldmapid
|
||||||
|
$game_player.moveto2(oldx, oldy)
|
||||||
|
$game_player.direction = olddirection
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleChallengeType
|
||||||
|
attr_accessor :currentWins
|
||||||
|
attr_accessor :previousWins
|
||||||
|
attr_accessor :maxWins
|
||||||
|
attr_accessor :currentSwaps
|
||||||
|
attr_accessor :previousSwaps
|
||||||
|
attr_accessor :maxSwaps
|
||||||
|
attr_reader :doublebattle
|
||||||
|
attr_reader :numPokemon
|
||||||
|
attr_reader :battletype
|
||||||
|
attr_reader :mode
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@previousWins = 0
|
||||||
|
@maxWins = 0
|
||||||
|
@currentWins = 0
|
||||||
|
@currentSwaps = 0
|
||||||
|
@previousSwaps = 0
|
||||||
|
@maxSwaps = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def saveWins(challenge)
|
||||||
|
if challenge.decision == 0 # if undecided
|
||||||
|
@currentWins = 0
|
||||||
|
@currentSwaps = 0
|
||||||
|
else
|
||||||
|
if challenge.decision == 1 # if won
|
||||||
|
@currentWins = challenge.wins
|
||||||
|
@currentSwaps = challenge.swaps
|
||||||
|
else # if lost
|
||||||
|
@currentWins = 0
|
||||||
|
@currentSwaps = 0
|
||||||
|
end
|
||||||
|
@maxWins = [@maxWins, challenge.wins].max
|
||||||
|
@previousWins = challenge.wins
|
||||||
|
@maxSwaps = [@maxSwaps, challenge.swaps].max
|
||||||
|
@previousSwaps = challenge.swaps
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Battle Factory data
|
||||||
|
#===============================================================================
|
||||||
|
class BattleFactoryData
|
||||||
|
def initialize(bcdata)
|
||||||
|
@bcdata = bcdata
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPrepareRentals
|
||||||
|
@rentals = pbBattleFactoryPokemon(pbBattleChallenge.rules, @bcdata.wins, @bcdata.swaps, [])
|
||||||
|
@trainerid = @bcdata.nextTrainer
|
||||||
|
bttrainers = pbGetBTTrainers(@bcdata.currentChallenge)
|
||||||
|
trainerdata = bttrainers[@trainerid]
|
||||||
|
@opponent = NPCTrainer.new(
|
||||||
|
pbGetMessageFromHash(MessageTypes::TrainerNames, trainerdata[1]),
|
||||||
|
trainerdata[0])
|
||||||
|
opponentPkmn = pbBattleFactoryPokemon(pbBattleChallenge.rules, @bcdata.wins, @bcdata.swaps, @rentals)
|
||||||
|
@opponent.party = opponentPkmn.shuffle[0, 3]
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbChooseRentals
|
||||||
|
pbFadeOutIn {
|
||||||
|
scene = BattleSwapScene.new
|
||||||
|
screen = BattleSwapScreen.new(scene)
|
||||||
|
@rentals = screen.pbStartRent(@rentals)
|
||||||
|
@bcdata.pbAddSwap
|
||||||
|
pbBattleChallenge.setParty(@rentals)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPrepareSwaps
|
||||||
|
@oldopponent = @opponent.party
|
||||||
|
trainerid = @bcdata.nextTrainer
|
||||||
|
bttrainers = pbGetBTTrainers(@bcdata.currentChallenge)
|
||||||
|
trainerdata = bttrainers[trainerid]
|
||||||
|
@opponent = NPCTrainer.new(
|
||||||
|
pbGetMessageFromHash(MessageTypes::TrainerNames, trainerdata[1]),
|
||||||
|
trainerdata[0])
|
||||||
|
opponentPkmn = pbBattleFactoryPokemon(challenge.rules, @bcdata.wins, @bcdata.swaps,
|
||||||
|
[].concat(@rentals).concat(@oldopponent))
|
||||||
|
@opponent.party = opponentPkmn.shuffle[0, 3]
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbChooseSwaps
|
||||||
|
swapMade = true
|
||||||
|
pbFadeOutIn {
|
||||||
|
scene = BattleSwapScene.new
|
||||||
|
screen = BattleSwapScreen.new(scene)
|
||||||
|
swapMade = screen.pbStartSwap(@rentals, @oldopponent)
|
||||||
|
@bcdata.pbAddSwap if swapMade
|
||||||
|
@bcdata.setParty(@rentals)
|
||||||
|
}
|
||||||
|
return swapMade
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattle(challenge)
|
||||||
|
bttrainers = pbGetBTTrainers(@bcdata.currentChallenge)
|
||||||
|
trainerdata = bttrainers[@trainerid]
|
||||||
|
return pbOrganizedBattleEx(@opponent, challenge.rules,
|
||||||
|
pbGetMessageFromHash(MessageTypes::EndSpeechLose, trainerdata[4]),
|
||||||
|
pbGetMessageFromHash(MessageTypes::EndSpeechWin, trainerdata[3]))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,223 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbBattleChallenge
|
||||||
|
$PokemonGlobal.challenge = BattleChallenge.new if !$PokemonGlobal.challenge
|
||||||
|
return $PokemonGlobal.challenge
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattleChallengeBattle
|
||||||
|
return pbBattleChallenge.pbBattle
|
||||||
|
end
|
||||||
|
|
||||||
|
# Used in events
|
||||||
|
def pbHasEligible?(*arg)
|
||||||
|
return pbBattleChallenge.rules.ruleset.hasValidTeam?($Trainer.party)
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbGetBTTrainers(challengeID)
|
||||||
|
trlists = (load_data("Data/trainer_lists.dat") rescue [])
|
||||||
|
trlists.each { |tr| return tr[0] if !tr[5] && tr[2].include?(challengeID) }
|
||||||
|
trlists.each { |tr| return tr[0] if tr[5] } # is default list
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbGetBTPokemon(challengeID)
|
||||||
|
trlists = (load_data("Data/trainer_lists.dat") rescue [])
|
||||||
|
trlists.each { |tr| return tr[1] if !tr[5] && tr[2].include?(challengeID) }
|
||||||
|
trlists.each { |tr| return tr[1] if tr[5] } # is default list
|
||||||
|
return []
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbEntryScreen(*arg)
|
||||||
|
retval = false
|
||||||
|
pbFadeOutIn {
|
||||||
|
scene = PokemonParty_Scene.new
|
||||||
|
screen = PokemonPartyScreen.new(scene, $Trainer.party)
|
||||||
|
ret = screen.pbPokemonMultipleEntryScreenEx(pbBattleChallenge.rules.ruleset)
|
||||||
|
# Set party
|
||||||
|
pbBattleChallenge.setParty(ret) if ret
|
||||||
|
# Continue (return true) if Pokémon were chosen
|
||||||
|
retval = (ret != nil && ret.length > 0)
|
||||||
|
}
|
||||||
|
return retval
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class Game_Player < Game_Character
|
||||||
|
def moveto2(x, y)
|
||||||
|
@x = x
|
||||||
|
@y = y
|
||||||
|
@real_x = @x * Game_Map::REAL_RES_X
|
||||||
|
@real_y = @y * Game_Map::REAL_RES_Y
|
||||||
|
@prelock_direction = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class Game_Event
|
||||||
|
def pbInChallenge?
|
||||||
|
return pbBattleChallenge.pbInChallenge?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbBattleChallengeGraphic(event)
|
||||||
|
nextTrainer = pbBattleChallenge.nextTrainer
|
||||||
|
bttrainers = pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
||||||
|
filename = GameData::TrainerType.charset_filename_brief((bttrainers[nextTrainer][0] rescue nil))
|
||||||
|
begin
|
||||||
|
filename = "NPC 01" if nil_or_empty?(filename)
|
||||||
|
bitmap = AnimatedBitmap.new("Graphics/Characters/" + filename)
|
||||||
|
bitmap.dispose
|
||||||
|
event.character_name = filename
|
||||||
|
rescue
|
||||||
|
event.character_name = "NPC 01"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattleChallengeBeginSpeech
|
||||||
|
return "..." if !pbBattleChallenge.pbInProgress?
|
||||||
|
bttrainers = pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
||||||
|
tr = bttrainers[pbBattleChallenge.nextTrainer]
|
||||||
|
return (tr) ? pbGetMessageFromHash(MessageTypes::BeginSpeech, tr[2]) : "..."
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class PBPokemon
|
||||||
|
attr_accessor :species
|
||||||
|
attr_accessor :item
|
||||||
|
attr_accessor :nature
|
||||||
|
attr_accessor :move1
|
||||||
|
attr_accessor :move2
|
||||||
|
attr_accessor :move3
|
||||||
|
attr_accessor :move4
|
||||||
|
attr_accessor :ev
|
||||||
|
|
||||||
|
# This method is how each Pokémon is compiled from the PBS files listing
|
||||||
|
# Battle Tower/Cup Pokémon.
|
||||||
|
def self.fromInspected(str)
|
||||||
|
insp = str.gsub(/^\s+/, "").gsub(/\s+$/, "")
|
||||||
|
pieces = insp.split(/\s*;\s*/)
|
||||||
|
species = (GameData::Species.exists?(pieces[0])) ? GameData::Species.get(pieces[0]).id : nil
|
||||||
|
item = (GameData::Item.exists?(pieces[1])) ? GameData::Item.get(pieces[1]).id : nil
|
||||||
|
nature = (GameData::Nature.exists?(pieces[2])) ? GameData::Nature.get(pieces[2]).id : nil
|
||||||
|
ev = pieces[3].split(/\s*,\s*/)
|
||||||
|
ev_array = []
|
||||||
|
ev.each do |stat|
|
||||||
|
case stat.upcase
|
||||||
|
when "HP" then ev_array.push(:HP)
|
||||||
|
when "ATK" then ev_array.push(:ATTACK)
|
||||||
|
when "DEF" then ev_array.push(:DEFENSE)
|
||||||
|
when "SA", "SPATK" then ev_array.push(:SPECIAL_ATTACK)
|
||||||
|
when "SD", "SPDEF" then ev_array.push(:SPECIAL_DEFENSE)
|
||||||
|
when "SPD" then ev_array.push(:SPEED)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
moves = pieces[4].split(/\s*,\s*/)
|
||||||
|
moveid = []
|
||||||
|
for i in 0...Pokemon::MAX_MOVES
|
||||||
|
move_data = GameData::Move.try_get(moves[i])
|
||||||
|
moveid.push(move_data.id) if move_data
|
||||||
|
end
|
||||||
|
if moveid.length == 0
|
||||||
|
GameData::Move.each { |mov| moveid.push(mov.id); break } # Get any one move
|
||||||
|
end
|
||||||
|
return self.new(species, item, nature, moveid[0], moveid[1], moveid[2], moveid[3], ev_array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.fromPokemon(pkmn)
|
||||||
|
mov1 = (pkmn.moves[0]) ? pkmn.moves[0].id : nil
|
||||||
|
mov2 = (pkmn.moves[1]) ? pkmn.moves[1].id : nil
|
||||||
|
mov3 = (pkmn.moves[2]) ? pkmn.moves[2].id : nil
|
||||||
|
mov4 = (pkmn.moves[3]) ? pkmn.moves[3].id : nil
|
||||||
|
ev_array = []
|
||||||
|
GameData::Stat.each_main do |s|
|
||||||
|
ev_array.push(s.id) if pkmn.ev[s.id] > 60
|
||||||
|
end
|
||||||
|
return self.new(pkmn.species, pkmn.item_id, pkmn.nature,
|
||||||
|
mov1, mov2, mov3, mov4, ev_array)
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(species, item, nature, move1, move2, move3, move4, ev)
|
||||||
|
@species = species
|
||||||
|
itm = GameData::Item.try_get(item)
|
||||||
|
@item = itm ? itm.id : nil
|
||||||
|
@nature = nature
|
||||||
|
@move1 = move1
|
||||||
|
@move2 = move2
|
||||||
|
@move3 = move3
|
||||||
|
@move4 = move4
|
||||||
|
@ev = ev
|
||||||
|
end
|
||||||
|
|
||||||
|
def inspect
|
||||||
|
c1 = GameData::Species.get(@species).id
|
||||||
|
c2 = (@item) ? GameData::Item.get(@item).id : ""
|
||||||
|
c3 = (@nature) ? GameData::Nature.get(@nature).id : ""
|
||||||
|
evlist = ""
|
||||||
|
@ev.each do |stat|
|
||||||
|
evlist += "," if evlist != ""
|
||||||
|
evlist += stat.real_name_brief
|
||||||
|
end
|
||||||
|
c4 = (@move1) ? GameData::Move.get(@move1).id : ""
|
||||||
|
c5 = (@move2) ? GameData::Move.get(@move2).id : ""
|
||||||
|
c6 = (@move3) ? GameData::Move.get(@move3).id : ""
|
||||||
|
c7 = (@move4) ? GameData::Move.get(@move4).id : ""
|
||||||
|
return "#{c1};#{c2};#{c3};#{evlist};#{c4},#{c5},#{c6},#{c7}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Unused.
|
||||||
|
def tocompact
|
||||||
|
return "#{species},#{item},#{nature},#{move1},#{move2},#{move3},#{move4},#{ev}"
|
||||||
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
|
def _dump(depth)
|
||||||
|
return [@species, @item, @nature, @move1, @move2, @move3, @move4, @ev].pack("vvCvvvvC")
|
||||||
|
end
|
||||||
|
|
||||||
|
def self._load(str)
|
||||||
|
data = str.unpack("vvCvvvvC")
|
||||||
|
return self.new(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7])
|
||||||
|
end
|
||||||
|
=end
|
||||||
|
|
||||||
|
def convertMove(move)
|
||||||
|
move = :FRUSTRATION if move == :RETURN && GameData::Move.exists?(:FRUSTRATION)
|
||||||
|
return move
|
||||||
|
end
|
||||||
|
|
||||||
|
def createPokemon(level, iv, trainer)
|
||||||
|
pkmn = Pokemon.new(@species, level, trainer, false)
|
||||||
|
pkmn.item = @item
|
||||||
|
pkmn.personalID = rand(2**16) | rand(2**16) << 16
|
||||||
|
pkmn.nature = nature
|
||||||
|
pkmn.happiness = 0
|
||||||
|
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move1)))
|
||||||
|
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move2))) if @move2
|
||||||
|
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move3))) if @move3
|
||||||
|
pkmn.moves.push(Pokemon::Move.new(self.convertMove(@move4))) if @move4
|
||||||
|
pkmn.moves.compact!
|
||||||
|
if ev.length > 0
|
||||||
|
ev.each { |stat| pkmn.ev[stat] = Pokemon::EV_LIMIT / ev.length }
|
||||||
|
end
|
||||||
|
GameData::Stat.each_main { |s| pkmn.iv[s.id] = iv }
|
||||||
|
pkmn.calc_stats
|
||||||
|
return pkmn
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,154 @@
|
|||||||
|
#===============================================================================
|
||||||
|
# Given an array of trainers and the number of wins the player already has,
|
||||||
|
# returns a random trainer index. The more wins, the later in the list the
|
||||||
|
# trainer comes from.
|
||||||
|
#===============================================================================
|
||||||
|
def pbBattleChallengeTrainer(win_count, bttrainers)
|
||||||
|
# This table's start points and lengths are based on a bttrainers size of 300.
|
||||||
|
# They are scaled based on the actual size of bttrainers later.
|
||||||
|
table = [ # Each value is [minimum win count, range start point, range length]
|
||||||
|
[ 0, 0, 100], # 0-100
|
||||||
|
[ 6, 80, 40], # 80-120
|
||||||
|
[ 7, 80, 40], # 80-120
|
||||||
|
[13, 120, 20], # 120-140
|
||||||
|
[14, 100, 40], # 100-140
|
||||||
|
[20, 140, 20], # 140-160
|
||||||
|
[21, 120, 40], # 120-160
|
||||||
|
[27, 160, 20], # 160-180
|
||||||
|
[28, 140, 40], # 140-180
|
||||||
|
[34, 180, 20], # 180-200
|
||||||
|
[35, 160, 40], # 160-200
|
||||||
|
[41, 200, 20], # 200-220
|
||||||
|
[42, 180, 40], # 180-220
|
||||||
|
[48, 220, 40], # 220-260
|
||||||
|
[49, 200, 100] # 200-300 - This line is used for all higher win_counts
|
||||||
|
]
|
||||||
|
slot = nil
|
||||||
|
table.each { |val| slot = val if val[0] <= win_count && slot[0] < val[0] }
|
||||||
|
return 0 if !slot
|
||||||
|
# Scale the start point and length based on how many trainers are in bttrainers
|
||||||
|
offset = slot[1] * bttrainers.length / 300
|
||||||
|
length = slot[2] * bttrainers.length / 300
|
||||||
|
# Return a random trainer index from the chosen range
|
||||||
|
return offset + rand(length)
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbGenerateBattleTrainer(idxTrainer, rules)
|
||||||
|
bttrainers = pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
||||||
|
btpokemon = pbGetBTPokemon(pbBattleChallenge.currentChallenge)
|
||||||
|
level = rules.ruleset.suggestedLevel
|
||||||
|
# Create the trainer
|
||||||
|
trainerdata = bttrainers[idxTrainer]
|
||||||
|
opponent = NPCTrainer.new(
|
||||||
|
pbGetMessageFromHash(MessageTypes::TrainerNames, trainerdata[1]),
|
||||||
|
trainerdata[0])
|
||||||
|
# Determine how many IVs the trainer's Pokémon will have
|
||||||
|
indvalues = 31
|
||||||
|
indvalues = 21 if idxTrainer < 220
|
||||||
|
indvalues = 18 if idxTrainer < 200
|
||||||
|
indvalues = 15 if idxTrainer < 180
|
||||||
|
indvalues = 12 if idxTrainer < 160
|
||||||
|
indvalues = 9 if idxTrainer < 140
|
||||||
|
indvalues = 6 if idxTrainer < 120
|
||||||
|
indvalues = 3 if idxTrainer < 100
|
||||||
|
# Get the indices within bypokemon of the Pokémon the trainer may have
|
||||||
|
pokemonnumbers = trainerdata[5]
|
||||||
|
# The number of possible Pokémon is <= the required number; make them
|
||||||
|
# all Pokémon and use them
|
||||||
|
if pokemonnumbers.length <= rules.ruleset.suggestedNumber
|
||||||
|
for n in pokemonnumbers
|
||||||
|
rndpoke = btpokemon[n]
|
||||||
|
pkmn = rndpoke.createPokemon(level, indvalues, opponent)
|
||||||
|
opponent.party.push(pkmn)
|
||||||
|
end
|
||||||
|
return opponent
|
||||||
|
end
|
||||||
|
# There are more possible Pokémon than there are spaces available in the
|
||||||
|
# trainer's party; randomly choose Pokémon
|
||||||
|
loop do
|
||||||
|
opponent.party.clear
|
||||||
|
while opponent.party.length < rules.ruleset.suggestedNumber
|
||||||
|
rnd = pokemonnumbers[rand(pokemonnumbers.length)]
|
||||||
|
rndpoke = btpokemon[rnd]
|
||||||
|
pkmn = rndpoke.createPokemon(level, indvalues, opponent)
|
||||||
|
opponent.party.push(pkmn)
|
||||||
|
end
|
||||||
|
break if rules.ruleset.isValid?(opponent.party)
|
||||||
|
end
|
||||||
|
return opponent
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Generate a full team's worth of Pokémon which obey the given rules.
|
||||||
|
#===============================================================================
|
||||||
|
def pbBattleFactoryPokemon(rules, win_count, swap_count, _rentals)
|
||||||
|
btpokemon = pbGetBTPokemon(pbBattleChallenge.currentChallenge)
|
||||||
|
level = rules.ruleset.suggestedLevel
|
||||||
|
pokemonNumbers = [0, 0] # Start and end indices in btpokemon
|
||||||
|
ivs = [0, 0] # Lower and higher IV values for Pokémon to use
|
||||||
|
iv_threshold = 6 # Number of Pokémon that use the lower IV
|
||||||
|
set = [win_count / 7, 7].min # The set of 7 battles win_count is part of (minus 1)
|
||||||
|
# Choose a range of Pokémon in btpokemon to randomly select from. The higher
|
||||||
|
# the set number, the later the range lies within btpokemon (typically).
|
||||||
|
# This table's start point and end point values are based on a btpokemon size
|
||||||
|
# of 882. They are scaled based on the actual size of btpokemon.
|
||||||
|
if level == GameData::GrowthRate.max_level # Open Level (Level 100)
|
||||||
|
table = [
|
||||||
|
[372, 467],
|
||||||
|
[468, 563],
|
||||||
|
[564, 659],
|
||||||
|
[660, 755],
|
||||||
|
[372, 881],
|
||||||
|
[372, 881],
|
||||||
|
[372, 881],
|
||||||
|
[372, 881] # This line is used for all higher sets
|
||||||
|
]
|
||||||
|
else
|
||||||
|
table = [
|
||||||
|
[110, 199],
|
||||||
|
[162, 266],
|
||||||
|
[267, 371],
|
||||||
|
[372, 467],
|
||||||
|
[468, 563],
|
||||||
|
[564, 659],
|
||||||
|
[660, 755],
|
||||||
|
[372, 849] # This line is used for all higher sets
|
||||||
|
]
|
||||||
|
end
|
||||||
|
pokemonNumbers[0] = table[set][0] * btpokemon.length / 882
|
||||||
|
pokemonNumbers[1] = table[set][1] * btpokemon.length / 882
|
||||||
|
# Choose two IV values for Pokémon to use (the one for the current set, and
|
||||||
|
# the one for the next set). The iv_threshold below determines which of these
|
||||||
|
# two values a given Pokémon uses. The higher the set number, the higher these
|
||||||
|
# values are.
|
||||||
|
ivtable = [3, 6, 9, 12, 15, 21, 31, 31] # Last value is used for all higher sets
|
||||||
|
ivs = [ivtable[set], ivtable[[set + 1, 7].min]]
|
||||||
|
# Choose a threshold, which is the number of Pokémon with the lower IV out of
|
||||||
|
# the two chosen above. The higher the swap_count, the lower this threshold
|
||||||
|
# (i.e. the more Pokémon will have the higher IV).
|
||||||
|
thresholds = [ # Each value is [minimum swap count, threshold value]
|
||||||
|
[ 0, 6],
|
||||||
|
[15, 5],
|
||||||
|
[22, 4],
|
||||||
|
[29, 3],
|
||||||
|
[36, 2],
|
||||||
|
[43, 1]
|
||||||
|
]
|
||||||
|
thresholds.each { |val| iv_threshold = val[1] if swap_count >= val[0] }
|
||||||
|
# Randomly choose Pokémon from the range to fill the party with
|
||||||
|
party = []
|
||||||
|
loop do
|
||||||
|
party.clear
|
||||||
|
while party.length < Settings::MAX_PARTY_SIZE
|
||||||
|
rnd = pokemonNumbers[0] + rand(pokemonNumbers[1] - pokemonNumbers[0] + 1)
|
||||||
|
rndpoke = btpokemon[rnd]
|
||||||
|
indvalue = (party.length < iv_threshold) ? ivs[0] : ivs[1]
|
||||||
|
party.push(rndpoke.createPokemon(level, indvalue, nil))
|
||||||
|
end
|
||||||
|
break if rules.ruleset.isValid?(party)
|
||||||
|
end
|
||||||
|
return party
|
||||||
|
end
|
||||||
@@ -0,0 +1,145 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleType
|
||||||
|
def pbCreateBattle(scene, trainer1, trainer2)
|
||||||
|
return PokeBattle_Battle.new(scene, trainer1.party, trainer2.party, trainer1, trainer2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleTower < BattleType
|
||||||
|
def pbCreateBattle(scene, trainer1, trainer2)
|
||||||
|
return PokeBattle_RecordedBattle.new(scene, trainer1.party, trainer2.party, trainer1, trainer2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattlePalace < BattleType
|
||||||
|
def pbCreateBattle(scene, trainer1, trainer2)
|
||||||
|
return PokeBattle_RecordedBattlePalace.new(scene, trainer1.party, trainer2.party, trainer1, trainer2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleArena < BattleType
|
||||||
|
def pbCreateBattle(scene, trainer1, trainer2)
|
||||||
|
return PokeBattle_RecordedBattleArena.new(scene, trainer1.party, trainer2.party, trainer1, trainer2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbOrganizedBattleEx(opponent, challengedata, endspeech, endspeechwin)
|
||||||
|
# Skip battle if holding Ctrl in Debug mode
|
||||||
|
if Input.press?(Input::CTRL) && $DEBUG
|
||||||
|
pbMessage(_INTL("SKIPPING BATTLE..."))
|
||||||
|
pbMessage(_INTL("AFTER WINNING..."))
|
||||||
|
endspeech.each { |msg| pbMessage(msg || "...") }
|
||||||
|
$PokemonTemp.lastbattle = nil
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
$Trainer.heal_party
|
||||||
|
# Remember original data, to be restored after battle
|
||||||
|
challengedata = PokemonChallengeRules.new if !challengedata
|
||||||
|
oldlevels = challengedata.adjustLevels($Trainer.party, opponent.party)
|
||||||
|
olditems = $Trainer.party.transform { |p| p.item_id }
|
||||||
|
olditems2 = opponent.party.transform { |p| p.item_id }
|
||||||
|
# Create the battle scene (the visual side of it)
|
||||||
|
scene = pbNewBattleScene
|
||||||
|
# Create the battle class (the mechanics side of it)
|
||||||
|
battle = challengedata.createBattle(scene, $Trainer, opponent)
|
||||||
|
battle.internalBattle = false
|
||||||
|
battle.endSpeeches = [endspeech]
|
||||||
|
battle.endSpeechesWin = [endspeechwin]
|
||||||
|
# Set various other properties in the battle class
|
||||||
|
pbPrepareBattle(battle)
|
||||||
|
# Perform the battle itself
|
||||||
|
decision = 0
|
||||||
|
pbBattleAnimation(pbGetTrainerBattleBGM(opponent)) {
|
||||||
|
pbSceneStandby {
|
||||||
|
decision = battle.pbStartBattle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Input.update
|
||||||
|
# Restore both parties to their original levels
|
||||||
|
challengedata.unadjustLevels($Trainer.party, opponent.party, oldlevels)
|
||||||
|
# Heal both parties and restore their original items
|
||||||
|
$Trainer.party.each_with_index do |pkmn, i|
|
||||||
|
pkmn.heal
|
||||||
|
pkmn.makeUnmega
|
||||||
|
pkmn.makeUnprimal
|
||||||
|
pkmn.item = olditems[i]
|
||||||
|
end
|
||||||
|
opponent.party.each_with_index do |pkmn, i|
|
||||||
|
pkmn.heal
|
||||||
|
pkmn.makeUnmega
|
||||||
|
pkmn.makeUnprimal
|
||||||
|
pkmn.item = olditems2[i]
|
||||||
|
end
|
||||||
|
# Save the record of the battle
|
||||||
|
$PokemonTemp.lastbattle = nil
|
||||||
|
if decision == 1 || decision == 2 || decision == 5 # if win, loss or draw
|
||||||
|
$PokemonTemp.lastbattle = battle.pbDumpRecord
|
||||||
|
end
|
||||||
|
# Return true if the player won the battle, and false if any other result
|
||||||
|
return (decision == 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Methods that record and play back a battle.
|
||||||
|
#===============================================================================
|
||||||
|
def pbRecordLastBattle
|
||||||
|
$PokemonGlobal.lastbattle = $PokemonTemp.lastbattle
|
||||||
|
$PokemonTemp.lastbattle = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPlayLastBattle
|
||||||
|
pbPlayBattle($PokemonGlobal.lastbattle)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPlayBattle(battledata)
|
||||||
|
return if !battledata
|
||||||
|
scene = pbNewBattleScene
|
||||||
|
scene.abortable = true
|
||||||
|
lastbattle = Marshal.restore(StringInput.new(battledata))
|
||||||
|
case lastbattle[0]
|
||||||
|
when BattleChallenge::BattleTowerID
|
||||||
|
battleplayer = PokeBattle_BattlePlayer.new(scene, lastbattle)
|
||||||
|
when BattleChallenge::BattlePalaceID
|
||||||
|
battleplayer = PokeBattle_BattlePalacePlayer.new(scene, lastbattle)
|
||||||
|
when BattleChallenge::BattleArenaID
|
||||||
|
battleplayer = PokeBattle_BattleArenaPlayer.new(scene, lastbattle)
|
||||||
|
end
|
||||||
|
bgm = BattlePlayerHelper.pbGetBattleBGM(lastbattle)
|
||||||
|
pbBattleAnimation(bgm) {
|
||||||
|
pbSceneStandby {
|
||||||
|
battleplayer.pbStartBattle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Debug playback methods.
|
||||||
|
#===============================================================================
|
||||||
|
def pbDebugPlayBattle
|
||||||
|
params = ChooseNumberParams.new
|
||||||
|
params.setRange(0, 500)
|
||||||
|
params.setInitialValue(0)
|
||||||
|
params.setCancelValue(-1)
|
||||||
|
num = pbMessageChooseNumber(_INTL("Choose a battle."), params)
|
||||||
|
if num >= 0
|
||||||
|
pbPlayBattleFromFile(sprintf("Battles/Battle%03d.dat", num))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPlayBattleFromFile(filename)
|
||||||
|
pbRgssOpen(filename, "rb") { |f| pbPlayBattle(f.read) }
|
||||||
|
end
|
||||||
@@ -0,0 +1,382 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class PokemonChallengeRules
|
||||||
|
attr_reader :ruleset
|
||||||
|
attr_reader :battletype
|
||||||
|
attr_reader :levelAdjustment
|
||||||
|
|
||||||
|
def initialize(ruleset = nil)
|
||||||
|
@ruleset = (ruleset) ? ruleset : PokemonRuleSet.new
|
||||||
|
@battletype = BattleTower.new
|
||||||
|
@levelAdjustment = nil
|
||||||
|
@battlerules = []
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy
|
||||||
|
ret = PokemonChallengeRules.new(@ruleset.copy)
|
||||||
|
ret.setBattleType(@battletype)
|
||||||
|
ret.setLevelAdjustment(@levelAdjustment)
|
||||||
|
for rule in @battlerules
|
||||||
|
ret.addBattleRule(rule)
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def setRuleset(rule)
|
||||||
|
@ruleset = rule
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def setBattleType(rule)
|
||||||
|
@battletype = rule
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def setLevelAdjustment(rule)
|
||||||
|
@levelAdjustment = rule
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def number
|
||||||
|
return self.ruleset.number
|
||||||
|
end
|
||||||
|
|
||||||
|
def setNumber(number)
|
||||||
|
self.ruleset.setNumber(number)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def setDoubleBattle(value)
|
||||||
|
if value
|
||||||
|
self.ruleset.setNumber(4)
|
||||||
|
self.addBattleRule(DoubleBattle.new)
|
||||||
|
else
|
||||||
|
self.ruleset.setNumber(3)
|
||||||
|
self.addBattleRule(SingleBattle.new)
|
||||||
|
end
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def adjustLevels(party1, party2)
|
||||||
|
return @levelAdjustment.adjustLevels(party1, party2) if @levelAdjustment
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def unadjustLevels(party1, party2, adjusts)
|
||||||
|
@levelAdjustment.unadjustLevels(party1, party2, adjusts) if @levelAdjustment && adjusts
|
||||||
|
end
|
||||||
|
|
||||||
|
def adjustLevelsBilateral(party1,party2)
|
||||||
|
if @levelAdjustment && @levelAdjustment.type == LevelAdjustment::BothTeams
|
||||||
|
return @levelAdjustment.adjustLevels(party1, party2)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def unadjustLevelsBilateral(party1,party2,adjusts)
|
||||||
|
if @levelAdjustment && adjusts && @levelAdjustment.type == LevelAdjustment::BothTeams
|
||||||
|
@levelAdjustment.unadjustLevels(party1, party2, adjusts)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def addPokemonRule(rule)
|
||||||
|
self.ruleset.addPokemonRule(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def addLevelRule(minLevel,maxLevel,totalLevel)
|
||||||
|
self.addPokemonRule(MinimumLevelRestriction.new(minLevel))
|
||||||
|
self.addPokemonRule(MaximumLevelRestriction.new(maxLevel))
|
||||||
|
self.addSubsetRule(TotalLevelRestriction.new(totalLevel))
|
||||||
|
self.setLevelAdjustment(TotalLevelAdjustment.new(minLevel, maxLevel, totalLevel))
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def addSubsetRule(rule)
|
||||||
|
self.ruleset.addSubsetRule(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def addTeamRule(rule)
|
||||||
|
self.ruleset.addTeamRule(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def addBattleRule(rule)
|
||||||
|
@battlerules.push(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def createBattle(scene, trainer1, trainer2)
|
||||||
|
battle = @battletype.pbCreateBattle(scene, trainer1, trainer2)
|
||||||
|
for p in @battlerules
|
||||||
|
p.setRule(battle)
|
||||||
|
end
|
||||||
|
return battle
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Stadium Cups rules
|
||||||
|
#===============================================================================
|
||||||
|
def pbPikaCupRules(double)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
ret.addPokemonRule(StandardRestriction.new)
|
||||||
|
ret.addLevelRule(15, 20, 50)
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SleepClause.new)
|
||||||
|
ret.addBattleRule(FreezeClause.new)
|
||||||
|
ret.addBattleRule(SelfKOClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
ret.setNumber(3)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPokeCupRules(double)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
ret.addPokemonRule(StandardRestriction.new)
|
||||||
|
ret.addLevelRule(50, 55, 155)
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SleepClause.new)
|
||||||
|
ret.addBattleRule(FreezeClause.new)
|
||||||
|
ret.addBattleRule(SelfdestructClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
ret.setNumber(3)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbPrimeCupRules(double)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
ret.setLevelAdjustment(OpenLevelAdjustment.new(GameData::GrowthRate.max_level))
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SleepClause.new)
|
||||||
|
ret.addBattleRule(FreezeClause.new)
|
||||||
|
ret.addBattleRule(SelfdestructClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbFancyCupRules(double)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
ret.addPokemonRule(StandardRestriction.new)
|
||||||
|
ret.addLevelRule(25, 30, 80)
|
||||||
|
ret.addPokemonRule(HeightRestriction.new(2))
|
||||||
|
ret.addPokemonRule(WeightRestriction.new(20))
|
||||||
|
ret.addPokemonRule(BabyRestriction.new)
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SleepClause.new)
|
||||||
|
ret.addBattleRule(FreezeClause.new)
|
||||||
|
ret.addBattleRule(PerishSongClause.new)
|
||||||
|
ret.addBattleRule(SelfdestructClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
ret.setNumber(3)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbLittleCupRules(double)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
ret.addPokemonRule(StandardRestriction.new)
|
||||||
|
ret.addPokemonRule(UnevolvedFormRestriction.new)
|
||||||
|
ret.setLevelAdjustment(EnemyLevelAdjustment.new(5))
|
||||||
|
ret.addPokemonRule(MaximumLevelRestriction.new(5))
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SleepClause.new)
|
||||||
|
ret.addBattleRule(FreezeClause.new)
|
||||||
|
ret.addBattleRule(SelfdestructClause.new)
|
||||||
|
ret.addBattleRule(PerishSongClause.new)
|
||||||
|
ret.addBattleRule(SonicBoomClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbStrictLittleCupRules(double)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
ret.addPokemonRule(StandardRestriction.new)
|
||||||
|
ret.addPokemonRule(UnevolvedFormRestriction.new)
|
||||||
|
ret.setLevelAdjustment(EnemyLevelAdjustment.new(5))
|
||||||
|
ret.addPokemonRule(MaximumLevelRestriction.new(5))
|
||||||
|
ret.addPokemonRule(LittleCupRestriction.new)
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addBattleRule(SleepClause.new)
|
||||||
|
ret.addBattleRule(EvasionClause.new)
|
||||||
|
ret.addBattleRule(OHKOClause.new)
|
||||||
|
ret.addBattleRule(SelfKOClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
ret.setNumber(3)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Battle Frontier rules
|
||||||
|
#===============================================================================
|
||||||
|
def pbBattleTowerRules(double, openlevel)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
if openlevel
|
||||||
|
ret.setLevelAdjustment(OpenLevelAdjustment.new(60))
|
||||||
|
else
|
||||||
|
ret.setLevelAdjustment(CappedLevelAdjustment.new(50))
|
||||||
|
end
|
||||||
|
ret.addPokemonRule(StandardRestriction.new)
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SoulDewBattleClause.new)
|
||||||
|
ret.setDoubleBattle(double)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattlePalaceRules(double, openlevel)
|
||||||
|
return pbBattleTowerRules(double, openlevel).setBattleType(BattlePalace.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattleArenaRules(openlevel)
|
||||||
|
return pbBattleTowerRules(false, openlevel).setBattleType(BattleArena.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbBattleFactoryRules(double, openlevel)
|
||||||
|
ret = PokemonChallengeRules.new
|
||||||
|
if openlevel
|
||||||
|
ret.setLevelAdjustment(FixedLevelAdjustment.new(100))
|
||||||
|
ret.addPokemonRule(MaximumLevelRestriction.new(100))
|
||||||
|
else
|
||||||
|
ret.setLevelAdjustment(FixedLevelAdjustment.new(50))
|
||||||
|
ret.addPokemonRule(MaximumLevelRestriction.new(50))
|
||||||
|
end
|
||||||
|
ret.addTeamRule(SpeciesClause.new)
|
||||||
|
ret.addPokemonRule(BannedSpeciesRestriction.new(:UNOWN))
|
||||||
|
ret.addTeamRule(ItemClause.new)
|
||||||
|
ret.addBattleRule(SoulDewBattleClause.new)
|
||||||
|
ret.setDoubleBattle(double).setNumber(0)
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Other Interesting Rulesets
|
||||||
|
#===============================================================================
|
||||||
|
=begin
|
||||||
|
# Official Species Restriction
|
||||||
|
.addPokemonRule(BannedSpeciesRestriction.new(
|
||||||
|
:MEWTWO, :MEW,
|
||||||
|
:LUGIA, :HOOH, :CELEBI,
|
||||||
|
:KYOGRE, :GROUDON, :RAYQUAZA, :JIRACHI, :DEOXYS,
|
||||||
|
:DIALGA, :PALKIA, :GIRATINA, :MANAPHY, :PHIONE,
|
||||||
|
:DARKRAI, :SHAYMIN, :ARCEUS))
|
||||||
|
.addBattleRule(SoulDewBattleClause.new)
|
||||||
|
|
||||||
|
# New Official Species Restriction
|
||||||
|
.addPokemonRule(BannedSpeciesRestriction.new(
|
||||||
|
:MEW,
|
||||||
|
:CELEBI,
|
||||||
|
:JIRACHI, :DEOXYS,
|
||||||
|
:MANAPHY, :PHIONE, :DARKRAI, :SHAYMIN, :ARCEUS))
|
||||||
|
.addBattleRule(SoulDewBattleClause.new)
|
||||||
|
|
||||||
|
# Pocket Monsters Stadium
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addPokemonRule(SpeciesRestriction.new(
|
||||||
|
:VENUSAUR, :CHARIZARD, :BLASTOISE, :BEEDRILL, :FEAROW,
|
||||||
|
:PIKACHU, :NIDOQUEEN, :NIDOKING, :DUGTRIO, :PRIMEAPE,
|
||||||
|
:ARCANINE, :ALAKAZAM, :MACHAMP, :GOLEM, :MAGNETON,
|
||||||
|
:CLOYSTER, :GENGAR, :ONIX, :HYPNO, :ELECTRODE,
|
||||||
|
:EXEGGUTOR, :CHANSEY, :KANGASKHAN, :STARMIE, :SCYTHER,
|
||||||
|
:JYNX, :PINSIR, :TAUROS, :GYARADOS, :LAPRAS,
|
||||||
|
:DITTO, :VAPOREON, :JOLTEON, :FLAREON, :AERODACTYL,
|
||||||
|
:SNORLAX, :ARTICUNO, :ZAPDOS, :MOLTRES, :DRAGONITE
|
||||||
|
))
|
||||||
|
|
||||||
|
# 1999 Tournament Rules
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addTeamRule(SpeciesClause.new)
|
||||||
|
.addPokemonRule(ItemsDisallowedClause.new)
|
||||||
|
.addBattleRule(SleepClause.new)
|
||||||
|
.addBattleRule(FreezeClause.new)
|
||||||
|
.addBattleRule(SelfdestructClause.new)
|
||||||
|
.setDoubleBattle(false)
|
||||||
|
.setLevelRule(1, 50, 150)
|
||||||
|
.addPokemonRule(BannedSpeciesRestriction.new(
|
||||||
|
:VENUSAUR, :DUGTRIO, :ALAKAZAM, :GOLEM, :MAGNETON,
|
||||||
|
:GENGAR, :HYPNO, :ELECTRODE, :EXEGGUTOR, :CHANSEY,
|
||||||
|
:KANGASKHAN, :STARMIE, :JYNX, :TAUROS, :GYARADOS,
|
||||||
|
:LAPRAS, :DITTO, :VAPOREON, :JOLTEON, :SNORLAX,
|
||||||
|
:ARTICUNO, :ZAPDOS, :DRAGONITE, :MEWTWO, :MEW))
|
||||||
|
|
||||||
|
# 2005 Tournament Rules
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addPokemonRule(BannedSpeciesRestriction.new(
|
||||||
|
:DRAGONITE, :MEW, :MEWTWO,
|
||||||
|
:TYRANITAR, :LUGIA, :CELEBI, :HOOH,
|
||||||
|
:GROUDON, :KYOGRE, :RAYQUAZA, :JIRACHI, :DEOXYS))
|
||||||
|
.setDoubleBattle(true)
|
||||||
|
.addLevelRule(1, 50, 200)
|
||||||
|
.addTeamRule(ItemClause.new)
|
||||||
|
.addPokemonRule(BannedItemRestriction.new(:SOULDEW, :ENIGMABERRY))
|
||||||
|
.addBattleRule(SleepClause.new)
|
||||||
|
.addBattleRule(FreezeClause.new)
|
||||||
|
.addBattleRule(SelfdestructClause.new)
|
||||||
|
.addBattleRule(PerishSongClause.new)
|
||||||
|
|
||||||
|
# 2008 Tournament Rules
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addPokemonRule(BannedSpeciesRestriction.new(
|
||||||
|
:MEWTWO, :MEW,
|
||||||
|
:TYRANITAR, :LUGIA, :HOOH, :CELEBI,
|
||||||
|
:GROUDON, :KYOGRE, :RAYQUAZA, :JIRACHI, :DEOXYS,
|
||||||
|
:PALKIA, :DIALGA, :PHIONE, :MANAPHY, :ROTOM, :SHAYMIN, :DARKRAI))
|
||||||
|
.setDoubleBattle(true)
|
||||||
|
.addLevelRule(1, 50, 200)
|
||||||
|
.addTeamRule(NicknameClause.new)
|
||||||
|
.addTeamRule(ItemClause.new)
|
||||||
|
.addBattleRule(SoulDewBattleClause.new)
|
||||||
|
|
||||||
|
# 2010 Tournament Rules
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addPokemonRule(BannedSpeciesRestriction.new(
|
||||||
|
:MEW,
|
||||||
|
:CELEBI,
|
||||||
|
:JIRACHI, :DEOXYS,
|
||||||
|
:PHIONE, :MANAPHY, :SHAYMIN, :DARKRAI, :ARCEUS))
|
||||||
|
.addSubsetRule(RestrictedSpeciesSubsetRestriction.new(
|
||||||
|
:MEWTWO,
|
||||||
|
:LUGIA, :HOOH,
|
||||||
|
:GROUDON, :KYOGRE, :RAYQUAZA,
|
||||||
|
:PALKIA, :DIALGA, :GIRATINA))
|
||||||
|
.setDoubleBattle(true)
|
||||||
|
.addLevelRule(1, 100, 600)
|
||||||
|
.setLevelAdjustment(CappedLevelAdjustment.new(50))
|
||||||
|
.addTeamRule(NicknameClause.new)
|
||||||
|
.addTeamRule(ItemClause.new)
|
||||||
|
.addPokemonRule(SoulDewClause.new)
|
||||||
|
|
||||||
|
# Pokemon Colosseum -- Anything Goes
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addLevelRule(1, 100, 600)
|
||||||
|
.addBattleRule(SleepClause.new)
|
||||||
|
.addBattleRule(FreezeClause.new)
|
||||||
|
.addBattleRule(SelfdestructClause.new)
|
||||||
|
.addBattleRule(PerishSongClause.new)
|
||||||
|
|
||||||
|
# Pokemon Colosseum -- Max Lv. 50
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addLevelRule(1, 50, 300)
|
||||||
|
.addTeamRule(SpeciesClause.new)
|
||||||
|
.addTeamRule(ItemClause.new)
|
||||||
|
.addBattleRule(SleepClause.new)
|
||||||
|
.addBattleRule(FreezeClause.new)
|
||||||
|
.addBattleRule(SelfdestructClause.new)
|
||||||
|
.addBattleRule(PerishSongClause.new)
|
||||||
|
|
||||||
|
# Pokemon Colosseum -- Max Lv. 100
|
||||||
|
PokemonChallengeRules.new
|
||||||
|
.addLevelRule(1, 100, 600)
|
||||||
|
.addTeamRule(SpeciesClause.new)
|
||||||
|
.addTeamRule(ItemClause.new)
|
||||||
|
.addBattleRule(SleepClause.new)
|
||||||
|
.addBattleRule(FreezeClause.new)
|
||||||
|
.addBattleRule(SelfdestructClause.new)
|
||||||
|
.addBattleRule(PerishSongClause.new)
|
||||||
|
=end
|
||||||
@@ -0,0 +1,324 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class PokemonRuleSet
|
||||||
|
def initialize(number = 0)
|
||||||
|
@pokemonRules = []
|
||||||
|
@teamRules = []
|
||||||
|
@subsetRules = []
|
||||||
|
@minLength = 1
|
||||||
|
@number = number
|
||||||
|
end
|
||||||
|
|
||||||
|
def copy
|
||||||
|
ret = PokemonRuleSet.new(@number)
|
||||||
|
for rule in @pokemonRules
|
||||||
|
ret.addPokemonRule(rule)
|
||||||
|
end
|
||||||
|
for rule in @teamRules
|
||||||
|
ret.addTeamRule(rule)
|
||||||
|
end
|
||||||
|
for rule in @subsetRules
|
||||||
|
ret.addSubsetRule(rule)
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def minLength
|
||||||
|
return (@minLength) ? @minLength : self.maxLength
|
||||||
|
end
|
||||||
|
|
||||||
|
def maxLength
|
||||||
|
return (@number < 0) ? 6 : @number
|
||||||
|
end
|
||||||
|
alias number maxLength
|
||||||
|
|
||||||
|
def minTeamLength
|
||||||
|
return [1, self.minLength].max
|
||||||
|
end
|
||||||
|
|
||||||
|
def maxTeamLength
|
||||||
|
return [6, self.maxLength].max
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns the length of a valid subset of a Pokemon team.
|
||||||
|
def suggestedNumber
|
||||||
|
return self.maxLength
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns a valid level to assign to each member of a valid Pokemon team.
|
||||||
|
def suggestedLevel
|
||||||
|
minLevel = 1
|
||||||
|
maxLevel = GameData::GrowthRate.max_level
|
||||||
|
num = self.suggestedNumber
|
||||||
|
for rule in @pokemonRules
|
||||||
|
if rule.is_a?(MinimumLevelRestriction)
|
||||||
|
minLevel = rule.level
|
||||||
|
elsif rule.is_a?(MaximumLevelRestriction)
|
||||||
|
maxLevel = rule.level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
totalLevel = maxLevel * num
|
||||||
|
for rule in @subsetRules
|
||||||
|
totalLevel = rule.level if rule.is_a?(TotalLevelRestriction)
|
||||||
|
end
|
||||||
|
return [maxLevel, minLevel].max if totalLevel >= maxLevel * num
|
||||||
|
return [totalLevel / self.suggestedNumber, minLevel].max
|
||||||
|
end
|
||||||
|
|
||||||
|
def setNumberRange(minValue, maxValue)
|
||||||
|
@minLength = [1, minValue].max
|
||||||
|
@number = [maxValue, 6].min
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def setNumber(value)
|
||||||
|
return setNumberRange(value, value)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This rule checks either:
|
||||||
|
# - the entire team to determine whether a subset of the team meets the rule, or
|
||||||
|
# - whether the entire team meets the rule. If the condition holds for the
|
||||||
|
# entire team, the condition must also hold for any possible subset of the
|
||||||
|
# team with the suggested number.
|
||||||
|
# Examples of team rules:
|
||||||
|
# - No two Pokemon can be the same species.
|
||||||
|
# - No two Pokemon can hold the same items.
|
||||||
|
def addTeamRule(rule)
|
||||||
|
@teamRules.push(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
# This rule checks:
|
||||||
|
# - the entire team to determine whether a subset of the team meets the rule, or
|
||||||
|
# - a list of Pokemon whose length is equal to the suggested number. For an
|
||||||
|
# entire team, the condition must hold for at least one possible subset of
|
||||||
|
# the team, but not necessarily for the entire team.
|
||||||
|
# A subset rule is "number-dependent", that is, whether the condition is likely
|
||||||
|
# to hold depends on the number of Pokemon in the subset.
|
||||||
|
# Example of a subset rule:
|
||||||
|
# - The combined level of X Pokemon can't exceed Y.
|
||||||
|
def addSubsetRule(rule)
|
||||||
|
@teamRules.push(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def addPokemonRule(rule)
|
||||||
|
@pokemonRules.push(rule)
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def clearTeamRules
|
||||||
|
@teamRules.clear
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def clearSubsetRules
|
||||||
|
@subsetRules.clear
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def clearPokemonRules
|
||||||
|
@pokemonRules.clear
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
|
||||||
|
def isPokemonValid?(pkmn)
|
||||||
|
return false if !pkmn
|
||||||
|
for rule in @pokemonRules
|
||||||
|
return false if !rule.isValid?(pkmn)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def hasRegistrableTeam?(list)
|
||||||
|
return false if !list || list.length < self.minTeamLength
|
||||||
|
pbEachCombination(list, self.maxTeamLength) { |comb|
|
||||||
|
return true if canRegisterTeam?(comb)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the team's length is greater or equal to the suggested number
|
||||||
|
# and is 6 or less, the team as a whole meets the requirements of any team
|
||||||
|
# rules, and at least one subset of the team meets the requirements of any
|
||||||
|
# subset rules. Each Pokemon in the team must be valid.
|
||||||
|
def canRegisterTeam?(team)
|
||||||
|
return false if !team || team.length < self.minTeamLength
|
||||||
|
return false if team.length > self.maxTeamLength
|
||||||
|
teamNumber = [self.maxLength, team.length].min
|
||||||
|
for pkmn in team
|
||||||
|
return false if !isPokemonValid?(pkmn)
|
||||||
|
end
|
||||||
|
for rule in @teamRules
|
||||||
|
return false if !rule.isValid?(team)
|
||||||
|
end
|
||||||
|
if @subsetRules.length > 0
|
||||||
|
pbEachCombination(team, teamNumber) { |comb|
|
||||||
|
isValid = true
|
||||||
|
for rule in @subsetRules
|
||||||
|
next if rule.isValid?(comb)
|
||||||
|
isValid = false
|
||||||
|
break
|
||||||
|
end
|
||||||
|
return true if isValid
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the team's length is greater or equal to the suggested number
|
||||||
|
# and at least one subset of the team meets the requirements of any team rules
|
||||||
|
# and subset rules. Not all Pokemon in the team have to be valid.
|
||||||
|
def hasValidTeam?(team)
|
||||||
|
return false if !team || team.length < self.minTeamLength
|
||||||
|
teamNumber = [self.maxLength, team.length].min
|
||||||
|
validPokemon = []
|
||||||
|
for pkmn in team
|
||||||
|
validPokemon.push(pkmn) if isPokemonValid?(pkmn)
|
||||||
|
end
|
||||||
|
return false if validPokemon.length < teamNumber
|
||||||
|
if @teamRules.length > 0
|
||||||
|
pbEachCombination(team, teamNumber) { |comb| return true if isValid?(comb) }
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns true if the team's length meets the subset length range requirements
|
||||||
|
# and the team meets the requirements of any team rules and subset rules. Each
|
||||||
|
# Pokemon in the team must be valid.
|
||||||
|
def isValid?(team, error = nil)
|
||||||
|
if team.length < self.minLength
|
||||||
|
error.push(_INTL("Choose a Pokémon.")) if error && self.minLength == 1
|
||||||
|
error.push(_INTL("{1} Pokémon are needed.", self.minLength)) if error && self.minLength > 1
|
||||||
|
return false
|
||||||
|
elsif team.length > self.maxLength
|
||||||
|
error.push(_INTL("No more than {1} Pokémon may enter.", self.maxLength)) if error
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for pkmn in team
|
||||||
|
next if isPokemonValid?(pkmn)
|
||||||
|
if pkmn
|
||||||
|
error.push(_INTL("This team is not allowed.", pkmn.name)) if error
|
||||||
|
else
|
||||||
|
error.push(_INTL("{1} is not allowed.", pkmn.name)) if error
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for rule in @teamRules
|
||||||
|
next if rule.isValid?(team)
|
||||||
|
error.push(rule.errorMessage) if error
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for rule in @subsetRules
|
||||||
|
next if rule.isValid?(team)
|
||||||
|
error.push(rule.errorMessage) if error
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class StandardRules < PokemonRuleSet
|
||||||
|
attr_reader :number
|
||||||
|
|
||||||
|
def initialize(number, level = nil)
|
||||||
|
super(number)
|
||||||
|
addPokemonRule(StandardRestriction.new)
|
||||||
|
addPokemonRule(SpeciesClause.new)
|
||||||
|
addPokemonRule(ItemClause.new)
|
||||||
|
addPokemonRule(MaximumLevelRestriction.new(level)) if level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
###########################################
|
||||||
|
# Generation IV Cups
|
||||||
|
###########################################
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class StandardCup < StandardRules
|
||||||
|
def initialize
|
||||||
|
super(3, 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
return _INTL("Standard Cup")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class DoubleCup < StandardRules
|
||||||
|
def initialize
|
||||||
|
super(4, 50)
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
return _INTL("Double Cup")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class FancyCup < PokemonRuleSet
|
||||||
|
def initialize
|
||||||
|
super(3)
|
||||||
|
addPokemonRule(StandardRestriction.new)
|
||||||
|
addPokemonRule(MaximumLevelRestriction.new(30))
|
||||||
|
addSubsetRule(TotalLevelRestriction.new(80))
|
||||||
|
addPokemonRule(HeightRestriction.new(2))
|
||||||
|
addPokemonRule(WeightRestriction.new(20))
|
||||||
|
addPokemonRule(BabyRestriction.new)
|
||||||
|
addPokemonRule(SpeciesClause.new)
|
||||||
|
addPokemonRule(ItemClause.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
return _INTL("Fancy Cup")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class LittleCup < PokemonRuleSet
|
||||||
|
def initialize
|
||||||
|
super(3)
|
||||||
|
addPokemonRule(StandardRestriction.new)
|
||||||
|
addPokemonRule(MaximumLevelRestriction.new(5))
|
||||||
|
addPokemonRule(BabyRestriction.new)
|
||||||
|
addPokemonRule(SpeciesClause.new)
|
||||||
|
addPokemonRule(ItemClause.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
return _INTL("Little Cup")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class LightCup < PokemonRuleSet
|
||||||
|
def initialize
|
||||||
|
super(3)
|
||||||
|
addPokemonRule(StandardRestriction.new)
|
||||||
|
addPokemonRule(MaximumLevelRestriction.new(50))
|
||||||
|
addPokemonRule(WeightRestriction.new(99))
|
||||||
|
addPokemonRule(BabyRestriction.new)
|
||||||
|
addPokemonRule(SpeciesClause.new)
|
||||||
|
addPokemonRule(ItemClause.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
def name
|
||||||
|
return _INTL("Light Cup")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,393 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class StandardRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return false if !pkmn || pkmn.egg?
|
||||||
|
# Species with disadvantageous abilities are not banned
|
||||||
|
pkmn.species_data.abilities.each do |a|
|
||||||
|
return true if [:TRUANT, :SLOWSTART].include?(a)
|
||||||
|
end
|
||||||
|
# Certain named species are not banned
|
||||||
|
return true if [:DRAGONITE, :SALAMENCE, :TYRANITAR].include?(pkmn.species)
|
||||||
|
# Certain named species are banned
|
||||||
|
return false if [:WYNAUT, :WOBBUFFET].include?(pkmn.species)
|
||||||
|
# Species with total base stat 600 or more are banned
|
||||||
|
bst = 0
|
||||||
|
pkmn.baseStats.each_value { |s| bst += s }
|
||||||
|
return false if bst >= 600
|
||||||
|
# Is valid
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class HeightRestriction
|
||||||
|
def initialize(maxHeightInMeters)
|
||||||
|
@level = maxHeightInMeters
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
height = (pkmn.is_a?(Pokemon)) ? pkmn.height : GameData::Species.get(pkmn).height
|
||||||
|
return height <= (@level * 10).round
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class WeightRestriction
|
||||||
|
def initialize(maxWeightInKg)
|
||||||
|
@level = maxWeightInKg
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
weight = (pkmn.is_a?(Pokemon)) ? pkmn.weight : GameData::Species.get(pkmn).weight
|
||||||
|
return weight <= (@level * 10).round
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Unused
|
||||||
|
#===============================================================================
|
||||||
|
class NegativeExtendedGameClause
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return false if pkmn.isSpecies?(:ARCEUS)
|
||||||
|
return false if pkmn.hasItem?(:MICLEBERRY)
|
||||||
|
return false if pkmn.hasItem?(:CUSTAPBERRY)
|
||||||
|
return false if pkmn.hasItem?(:JABOCABERRY)
|
||||||
|
return false if pkmn.hasItem?(:ROWAPBERRY)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
$babySpeciesData = {}
|
||||||
|
|
||||||
|
class BabyRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
if !$babySpeciesData[pkmn.species]
|
||||||
|
$babySpeciesData[pkmn.species] = pkmn.species_data.get_baby_species
|
||||||
|
end
|
||||||
|
return pkmn.species == $babySpeciesData[pkmn.species]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
$canEvolve = {}
|
||||||
|
|
||||||
|
class UnevolvedFormRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
if !$babySpeciesData[pkmn.species]
|
||||||
|
$babySpeciesData[pkmn.species] = pkmn.species_data.get_baby_species
|
||||||
|
end
|
||||||
|
return false if pkmn.species != $babySpeciesData[pkmn.species]
|
||||||
|
if $canEvolve[pkmn.species].nil?
|
||||||
|
$canEvolve[pkmn.species] = (pkmn.species_data.get_evolutions(true).length > 0)
|
||||||
|
end
|
||||||
|
return $canEvolve[pkmn.species]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
module NicknameChecker
|
||||||
|
@@names = {}
|
||||||
|
|
||||||
|
def getName(species)
|
||||||
|
n = @@names[species]
|
||||||
|
return n if n
|
||||||
|
n = GameData::Species.get(species).name
|
||||||
|
@@names[species] = n.upcase
|
||||||
|
return n
|
||||||
|
end
|
||||||
|
|
||||||
|
def check(name, species)
|
||||||
|
name = name.upcase
|
||||||
|
return true if name == getName(species)
|
||||||
|
return false if @@names.values.include?(name)
|
||||||
|
GameData::Species.each do |species_data|
|
||||||
|
next if species_data.species == species || species_data.form != 0
|
||||||
|
return false if getName(species_data.id) == name
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# No two Pokemon can have the same nickname.
|
||||||
|
# No nickname can be the same as the (real) name of another Pokemon character.
|
||||||
|
#===============================================================================
|
||||||
|
class NicknameClause
|
||||||
|
def isValid?(team)
|
||||||
|
for i in 0...team.length - 1
|
||||||
|
for j in i + 1...team.length
|
||||||
|
return false if team[i].name == team[j].name
|
||||||
|
return false if !NicknameChecker.check(team[i].name, team[i].species)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def errorMessage
|
||||||
|
return _INTL("No identical nicknames.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class NonEggRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return pkmn && !pkmn.egg?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class AblePokemonRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return pkmn && pkmn.able?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SpeciesRestriction
|
||||||
|
def initialize(*specieslist)
|
||||||
|
@specieslist = specieslist.clone
|
||||||
|
end
|
||||||
|
|
||||||
|
def isSpecies?(species, specieslist)
|
||||||
|
return specieslist.include?(species)
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return isSpecies?(pkmn.species, @specieslist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BannedSpeciesRestriction
|
||||||
|
def initialize(*specieslist)
|
||||||
|
@specieslist = specieslist.clone
|
||||||
|
end
|
||||||
|
|
||||||
|
def isSpecies?(species, specieslist)
|
||||||
|
return specieslist.include?(species)
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return !isSpecies?(pkmn.species, @specieslist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class RestrictedSpeciesRestriction
|
||||||
|
def initialize(maxValue, *specieslist)
|
||||||
|
@specieslist = specieslist.clone
|
||||||
|
@maxValue = maxValue
|
||||||
|
end
|
||||||
|
|
||||||
|
def isSpecies?(species, specieslist)
|
||||||
|
return specieslist.include?(species)
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(team)
|
||||||
|
count = 0
|
||||||
|
team.each do |pkmn|
|
||||||
|
count += 1 if pkmn && isSpecies?(pkmn.species, @specieslist)
|
||||||
|
end
|
||||||
|
return count <= @maxValue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class RestrictedSpeciesTeamRestriction < RestrictedSpeciesRestriction
|
||||||
|
def initialize(*specieslist)
|
||||||
|
super(4, *specieslist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class RestrictedSpeciesSubsetRestriction < RestrictedSpeciesRestriction
|
||||||
|
def initialize(*specieslist)
|
||||||
|
super(2, *specieslist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SameSpeciesClause
|
||||||
|
def isValid?(team)
|
||||||
|
species = []
|
||||||
|
team.each do |pkmn|
|
||||||
|
species.push(pkmn.species) if pkmn && !species.include?(pkmn.species)
|
||||||
|
end
|
||||||
|
return species.length == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
def errorMessage
|
||||||
|
return _INTL("Pokémon must be the same species.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SpeciesClause
|
||||||
|
def isValid?(team)
|
||||||
|
species = []
|
||||||
|
team.each do |pkmn|
|
||||||
|
next if !pkmn
|
||||||
|
return false if species.include?(pkmn.species)
|
||||||
|
species.push(pkmn.species)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def errorMessage
|
||||||
|
return _INTL("Pokémon can't be the same species.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class MinimumLevelRestriction
|
||||||
|
attr_reader :level
|
||||||
|
|
||||||
|
def initialize(minLevel)
|
||||||
|
@level = minLevel
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return pkmn.level >= @level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class MaximumLevelRestriction
|
||||||
|
attr_reader :level
|
||||||
|
|
||||||
|
def initialize(maxLevel)
|
||||||
|
@level = maxLevel
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return pkmn.level <= @level
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class TotalLevelRestriction
|
||||||
|
attr_reader :level
|
||||||
|
|
||||||
|
def initialize(level)
|
||||||
|
@level = level
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(team)
|
||||||
|
totalLevel = 0
|
||||||
|
team.each { |pkmn| totalLevel += pkmn.level if pkmn }
|
||||||
|
return totalLevel <= @level
|
||||||
|
end
|
||||||
|
|
||||||
|
def errorMessage
|
||||||
|
return _INTL("The combined levels exceed {1}.", @level)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BannedItemRestriction
|
||||||
|
def initialize(*itemlist)
|
||||||
|
@itemlist = itemlist.clone
|
||||||
|
end
|
||||||
|
|
||||||
|
def isSpecies?(item,itemlist)
|
||||||
|
return itemlist.include?(item)
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return !pkmn.item_id || !isSpecies?(pkmn.item_id, @itemlist)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class ItemsDisallowedClause
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return !pkmn.hasItem?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SoulDewClause
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return !pkmn.hasItem?(:SOULDEW)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class ItemClause
|
||||||
|
def isValid?(team)
|
||||||
|
items = []
|
||||||
|
team.each do |pkmn|
|
||||||
|
next if !pkmn || !pkmn.hasItem?
|
||||||
|
return false if items.include?(pkmn.item_id)
|
||||||
|
items.push(pkmn.item_id)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
def errorMessage
|
||||||
|
return _INTL("No identical hold items.")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class LittleCupRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return false if pkmn.hasItem?(:BERRYJUICE)
|
||||||
|
return false if pkmn.hasItem?(:DEEPSEATOOTH)
|
||||||
|
return false if pkmn.hasMove?(:SONICBOOM)
|
||||||
|
return false if pkmn.hasMove?(:DRAGONRAGE)
|
||||||
|
return false if pkmn.isSpecies?(:SCYTHER)
|
||||||
|
return false if pkmn.isSpecies?(:SNEASEL)
|
||||||
|
return false if pkmn.isSpecies?(:MEDITITE)
|
||||||
|
return false if pkmn.isSpecies?(:YANMA)
|
||||||
|
return false if pkmn.isSpecies?(:TANGELA)
|
||||||
|
return false if pkmn.isSpecies?(:MURKROW)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,227 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class LevelAdjustment
|
||||||
|
BothTeams = 0
|
||||||
|
EnemyTeam = 1
|
||||||
|
MyTeam = 2
|
||||||
|
BothTeamsDifferent = 3
|
||||||
|
|
||||||
|
def initialize(adjustment)
|
||||||
|
@adjustment = adjustment
|
||||||
|
end
|
||||||
|
|
||||||
|
def type
|
||||||
|
@adjustment
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.getNullAdjustment(thisTeam, _otherTeam)
|
||||||
|
ret = []
|
||||||
|
thisTeam.each_with_index { |pkmn, i| ret[i] = pkmn.level }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, otherTeam)
|
||||||
|
return self.getNullAdjustment(thisTeam, otherTeam)
|
||||||
|
end
|
||||||
|
|
||||||
|
def getOldExp(team1, _team2)
|
||||||
|
ret = []
|
||||||
|
team1.each_with_index { |pkmn, i| ret[i] = pkmn.exp }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def unadjustLevels(team1, team2, adjustments)
|
||||||
|
team1.each_with_index do |pkmn, i|
|
||||||
|
next if !adjustments[0][i] || pkmn.exp == adjustments[0][i]
|
||||||
|
pkmn.exp = adjustments[0][i]
|
||||||
|
pkmn.calc_stats
|
||||||
|
end
|
||||||
|
team2.each_with_index do |pkmn, i|
|
||||||
|
next if !adjustments[1][i] || pkmn.exp == adjustments[1][i]
|
||||||
|
pkmn.exp = adjustments[1][i]
|
||||||
|
pkmn.calc_stats
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def adjustLevels(team1, team2)
|
||||||
|
adj1 = nil
|
||||||
|
adj2 = nil
|
||||||
|
ret = [getOldExp(team1, team2), getOldExp(team2, team1)]
|
||||||
|
if @adjustment == BothTeams || @adjustment == MyTeam
|
||||||
|
adj1 = getAdjustment(team1, team2)
|
||||||
|
elsif @adjustment == BothTeamsDifferent
|
||||||
|
adj1 = getMyAdjustment(team1, team2)
|
||||||
|
end
|
||||||
|
if @adjustment == BothTeams || @adjustment == EnemyTeam
|
||||||
|
adj2 = getAdjustment(team2, team1)
|
||||||
|
elsif @adjustment == BothTeamsDifferent
|
||||||
|
adj2 = getTheirAdjustment(team2, team1)
|
||||||
|
end
|
||||||
|
if adj1
|
||||||
|
team1.each_with_index do |pkmn, i|
|
||||||
|
next if pkmn.level == adj1[i]
|
||||||
|
pkmn.level = adj1[i]
|
||||||
|
pkmn.calc_stats
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if adj2
|
||||||
|
team2.each_with_index do |pkmn, i|
|
||||||
|
next if pkmn.level == adj2[i]
|
||||||
|
pkmn.level = adj2[i]
|
||||||
|
pkmn.calc_stats
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class FixedLevelAdjustment < LevelAdjustment
|
||||||
|
def initialize(level)
|
||||||
|
super(LevelAdjustment::BothTeams)
|
||||||
|
@level = level.clamp(1, GameData::GrowthRate.max_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, _otherTeam)
|
||||||
|
ret = []
|
||||||
|
thisTeam.each_with_index { |pkmn, i| ret[i] = @level }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class TotalLevelAdjustment < LevelAdjustment
|
||||||
|
def initialize(minLevel, maxLevel, totalLevel)
|
||||||
|
super(LevelAdjustment::EnemyTeam)
|
||||||
|
@minLevel = minLevel.clamp(1, GameData::GrowthRate.max_level)
|
||||||
|
@maxLevel = maxLevel.clamp(1, GameData::GrowthRate.max_level)
|
||||||
|
@totalLevel=totalLevel
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, _otherTeam)
|
||||||
|
ret = []
|
||||||
|
total = 0
|
||||||
|
thisTeam.each_with_index do |pkmn, i|
|
||||||
|
ret[i] = @minLevel
|
||||||
|
total += @minLevel
|
||||||
|
end
|
||||||
|
loop do
|
||||||
|
work = false
|
||||||
|
thisTeam.each_with_index do |pkmn, i|
|
||||||
|
next if ret[i] >= @maxLevel || total >= @totalLevel
|
||||||
|
ret[i] += 1
|
||||||
|
total += 1
|
||||||
|
work = true
|
||||||
|
end
|
||||||
|
break if !work
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class CombinedLevelAdjustment < LevelAdjustment
|
||||||
|
def initialize(my, their)
|
||||||
|
super(LevelAdjustment::BothTeamsDifferent)
|
||||||
|
@my = my
|
||||||
|
@their = their
|
||||||
|
end
|
||||||
|
|
||||||
|
def getMyAdjustment(myTeam,theirTeam)
|
||||||
|
return @my.getAdjustment(myTeam, theirTeam) if @my
|
||||||
|
return LevelAdjustment.getNullAdjustment(myTeam, theirTeam)
|
||||||
|
end
|
||||||
|
|
||||||
|
def getTheirAdjustment(theirTeam,myTeam)
|
||||||
|
return @their.getAdjustment(theirTeam, myTeam) if @their
|
||||||
|
return LevelAdjustment.getNullAdjustment(theirTeam, myTeam)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SinglePlayerCappedLevelAdjustment < CombinedLevelAdjustment
|
||||||
|
def initialize(level)
|
||||||
|
super(CappedLevelAdjustment.new(level), FixedLevelAdjustment.new(level))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class CappedLevelAdjustment < LevelAdjustment
|
||||||
|
def initialize(level)
|
||||||
|
super(LevelAdjustment::BothTeams)
|
||||||
|
@level = level.clamp(1, GameData::GrowthRate.max_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, _otherTeam)
|
||||||
|
ret = []
|
||||||
|
thisTeam.each_with_index { |pkmn, i| ret[i] = [pkmn.level, @level].min }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Unused
|
||||||
|
#===============================================================================
|
||||||
|
class LevelBalanceAdjustment < LevelAdjustment
|
||||||
|
def initialize(minLevel)
|
||||||
|
super(LevelAdjustment::BothTeams)
|
||||||
|
@minLevel = minLevel
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, _otherTeam)
|
||||||
|
ret = []
|
||||||
|
thisTeam.each_with_index do |pkmn, i|
|
||||||
|
ret[i] = (113 - (pbBaseStatTotal(pkmn.species) * 0.072)).round
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class EnemyLevelAdjustment < LevelAdjustment
|
||||||
|
def initialize(level)
|
||||||
|
super(LevelAdjustment::EnemyTeam)
|
||||||
|
@level = level.clamp(1, GameData::GrowthRate.max_level)
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, _otherTeam)
|
||||||
|
ret = []
|
||||||
|
thisTeam.each_with_index { |pkmn, i| ret[i] = @level }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class OpenLevelAdjustment < LevelAdjustment
|
||||||
|
def initialize(minLevel = 1)
|
||||||
|
super(LevelAdjustment::EnemyTeam)
|
||||||
|
@minLevel = minLevel
|
||||||
|
end
|
||||||
|
|
||||||
|
def getAdjustment(thisTeam, otherTeam)
|
||||||
|
maxLevel = 1
|
||||||
|
otherTeam.each do |pkmn|
|
||||||
|
level = pkmn.level
|
||||||
|
maxLevel = level if maxLevel < level
|
||||||
|
end
|
||||||
|
maxLevel = @minLevel if maxLevel < @minLevel
|
||||||
|
ret = []
|
||||||
|
thisTeam.each_with_index { |pkmn, i| ret[i] = maxLevel }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BattleRule
|
||||||
|
def setRule(battle); end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class DoubleBattle < BattleRule
|
||||||
|
def setRule(battle); battle.setBattleMode("double"); end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SingleBattle < BattleRule
|
||||||
|
def setRule(battle); battle.setBattleMode("single"); end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SoulDewBattleClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["souldewclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SleepClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["sleepclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class FreezeClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["freezeclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class EvasionClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["evasionclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class OHKOClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["ohkoclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class PerishSongClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["perishsong"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SelfKOClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["selfkoclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SelfdestructClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["selfdestructclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SonicBoomClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["sonicboomclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class ModifiedSleepClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["modifiedsleepclause"] = true; end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SkillSwapClause < BattleRule
|
||||||
|
def setRule(battle); battle.rules["skillswapclause"] = true; end
|
||||||
|
end
|
||||||
@@ -0,0 +1,344 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class BaseStatRestriction
|
||||||
|
def initialize(mn, mx)
|
||||||
|
@mn = mn
|
||||||
|
@mx = mx
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
bst = baseStatTotal(pkmn.species)
|
||||||
|
return bst >= @mn && bst <= @mx
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class NonlegendaryRestriction
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return true if !pkmn.genderless?
|
||||||
|
return false if pkmn.species_data.egg_groups.include?(:Undiscovered)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class InverseRestriction
|
||||||
|
def initialize(r)
|
||||||
|
@r = r
|
||||||
|
end
|
||||||
|
|
||||||
|
def isValid?(pkmn)
|
||||||
|
return !@r.isValid?(pkmn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
=begin
|
||||||
|
[3/10]
|
||||||
|
0-266 - 0-500
|
||||||
|
[106]
|
||||||
|
267-372 - 380-500
|
||||||
|
[95]
|
||||||
|
373-467 - 400-555 (nonlegendary)
|
||||||
|
468-563 - 400-555 (nonlegendary)
|
||||||
|
564-659 - 400-555 (nonlegendary)
|
||||||
|
660-755 - 400-555 (nonlegendary)
|
||||||
|
756-799 - 580-600 [legendary] (compat1==15 or compat2==15, genderbyte=255)
|
||||||
|
800-849 - 500-
|
||||||
|
850-881 - 580-
|
||||||
|
=end
|
||||||
|
|
||||||
|
def withRestr(_rule, minbs, maxbs, legendary)
|
||||||
|
ret = PokemonChallengeRules.new.addPokemonRule(BaseStatRestriction.new(minbs, maxbs))
|
||||||
|
if legendary == 0
|
||||||
|
ret.addPokemonRule(NonlegendaryRestriction.new)
|
||||||
|
elsif legendary == 1
|
||||||
|
ret.addPokemonRule(InverseRestriction.new(NonlegendaryRestriction.new))
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbArrangeByTier(pokemonlist, rule)
|
||||||
|
tiers = [
|
||||||
|
withRestr(rule, 0, 500, 0),
|
||||||
|
withRestr(rule, 380, 500, 0),
|
||||||
|
withRestr(rule, 400, 555, 0),
|
||||||
|
withRestr(rule, 400, 555, 0),
|
||||||
|
withRestr(rule, 400, 555, 0),
|
||||||
|
withRestr(rule, 400, 555, 0),
|
||||||
|
withRestr(rule, 580, 680, 1),
|
||||||
|
withRestr(rule, 500, 680, 0),
|
||||||
|
withRestr(rule, 580, 680, 2)
|
||||||
|
]
|
||||||
|
tierPokemon = []
|
||||||
|
tiers.length.times do
|
||||||
|
tierPokemon.push([])
|
||||||
|
end
|
||||||
|
# Sort each Pokémon into tiers. Which tier a Pokémon is put in deoends on the
|
||||||
|
# Pokémon's position within pokemonlist (later = higher tier). pokemonlist is
|
||||||
|
# already roughly arranged by rank from weakest to strongest.
|
||||||
|
for i in 0...pokemonlist.length
|
||||||
|
next if !rule.ruleset.isPokemonValid?(pokemonlist[i])
|
||||||
|
validtiers = []
|
||||||
|
for j in 0...tiers.length
|
||||||
|
validtiers.push(j) if tiers[j].ruleset.isPokemonValid?(pokemonlist[i])
|
||||||
|
end
|
||||||
|
if validtiers.length > 0
|
||||||
|
vt = validtiers.length * i / pokemonlist.length
|
||||||
|
tierPokemon[validtiers[vt]].push(pokemonlist[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# Now for each tier, sort the Pokemon in that tier by their BST (lowest first).
|
||||||
|
ret = []
|
||||||
|
for i in 0...tiers.length
|
||||||
|
tierPokemon[i].sort! { |a, b|
|
||||||
|
bstA = baseStatTotal(a.species)
|
||||||
|
bstB = baseStatTotal(b.species)
|
||||||
|
(bstA == bstB) ? a.species <=> b.species : bstA <=> bstB
|
||||||
|
}
|
||||||
|
ret.concat(tierPokemon[i])
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbReplenishBattlePokemon(party, rule)
|
||||||
|
while party.length < 20
|
||||||
|
pkmn = pbRandomPokemonFromRule(rule, nil)
|
||||||
|
found = false
|
||||||
|
for pk in party
|
||||||
|
next if !isBattlePokemonDuplicate(pkmn, pk)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
party.push(pkmn) if !found
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def isBattlePokemonDuplicate(pk, pk2)
|
||||||
|
return false if pk.species != pk2.species
|
||||||
|
moves1 = []
|
||||||
|
moves2 = []
|
||||||
|
for i in 0...Pokemon::MAX_MOVES
|
||||||
|
moves1.push((pk.moves[i]) ? pk.moves[i].id : nil)
|
||||||
|
moves2.push((pk2.moves[i]) ? pk2.moves[i].id : nil)
|
||||||
|
end
|
||||||
|
moves1.sort!
|
||||||
|
moves2.sort!
|
||||||
|
# Accept as same if moves are same and there are four moves each
|
||||||
|
return true if moves1 == moves2 && moves1[Pokemon::MAX_MOVES - 1]
|
||||||
|
same_evs = true
|
||||||
|
GameData::Stat.each_main { |s| same_evs = false if pk.ev[s.id] != pk2.ev[s.id] }
|
||||||
|
return pk.item_id == pk2.item_id && pk.nature_id == pk2.nature_id && same_evs
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbRemoveDuplicates(party)
|
||||||
|
ret = []
|
||||||
|
for pk in party
|
||||||
|
found = false
|
||||||
|
count = 0
|
||||||
|
firstIndex = -1
|
||||||
|
for i in 0...ret.length
|
||||||
|
pk2 = ret[i]
|
||||||
|
if isBattlePokemonDuplicate(pk, pk2)
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if pk.species == pk2.species
|
||||||
|
firstIndex = i if count == 0
|
||||||
|
count += 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if !found
|
||||||
|
ret.delete_at(firstIndex) if count >= 10
|
||||||
|
ret.push(pk)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbGenerateChallenge(rule, tag)
|
||||||
|
oldrule = rule
|
||||||
|
yield(_INTL("Preparing to generate teams"))
|
||||||
|
rule = rule.copy.setNumber(2)
|
||||||
|
yield(nil)
|
||||||
|
party = load_data(tag + ".rxdata") rescue []
|
||||||
|
teams = load_data(tag + "teams.rxdata") rescue []
|
||||||
|
if teams.length < 10
|
||||||
|
btpokemon = pbGetBTPokemon(tag)
|
||||||
|
if btpokemon && btpokemon.length != 0
|
||||||
|
suggestedLevel = rule.ruleset.suggestedLevel
|
||||||
|
for pk in btpokemon
|
||||||
|
pkmn = pk.createPokemon(suggestedLevel, 31, nil)
|
||||||
|
party.push(pkmn) if rule.ruleset.isPokemonValid?(pkmn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
yield(nil)
|
||||||
|
party = pbRemoveDuplicates(party)
|
||||||
|
yield(nil)
|
||||||
|
maxteams = 600
|
||||||
|
cutoffrating = 65
|
||||||
|
toolowrating = 40
|
||||||
|
iterations = 11
|
||||||
|
iterations.times do |iter|
|
||||||
|
save_data(party, tag + ".rxdata")
|
||||||
|
yield(_INTL("Generating teams ({1} of {2})", iter + 1, iterations))
|
||||||
|
i = 0
|
||||||
|
while i < teams.length
|
||||||
|
yield(nil) if i % 10 == 0
|
||||||
|
pbReplenishBattlePokemon(party, rule)
|
||||||
|
if teams[i].rating < cutoffrating && teams[i].totalGames >= 80
|
||||||
|
teams[i] = RuledTeam.new(party, rule)
|
||||||
|
elsif teams[i].length < 2
|
||||||
|
teams[i] = RuledTeam.new(party, rule)
|
||||||
|
elsif i >= maxteams
|
||||||
|
teams[i] = nil
|
||||||
|
teams.compact!
|
||||||
|
elsif teams[i].totalGames >= 250
|
||||||
|
# retire
|
||||||
|
for j in 0...teams[i].length
|
||||||
|
party.push(teams[i][j])
|
||||||
|
end
|
||||||
|
teams[i] = RuledTeam.new(party,rule)
|
||||||
|
elsif teams[i].rating < toolowrating
|
||||||
|
teams[i] = RuledTeam.new(party,rule)
|
||||||
|
end
|
||||||
|
i += 1
|
||||||
|
end
|
||||||
|
save_data(teams, tag + "teams.rxdata")
|
||||||
|
yield(nil)
|
||||||
|
while teams.length < maxteams
|
||||||
|
yield(nil) if teams.length % 10 == 0
|
||||||
|
pbReplenishBattlePokemon(party, rule)
|
||||||
|
teams.push(RuledTeam.new(party, rule))
|
||||||
|
end
|
||||||
|
save_data(party, tag + ".rxdata")
|
||||||
|
teams = teams.sort { |a, b| b.rating <=> a.rating }
|
||||||
|
yield(_INTL("Simulating battles ({1} of {2})", iter + 1, iterations))
|
||||||
|
i = 0
|
||||||
|
loop do
|
||||||
|
changed = false
|
||||||
|
teams.length.times { |j|
|
||||||
|
yield(nil)
|
||||||
|
other = j
|
||||||
|
5.times do
|
||||||
|
other = rand(teams.length)
|
||||||
|
next if other == j
|
||||||
|
end
|
||||||
|
next if other == j
|
||||||
|
changed = true
|
||||||
|
pbRuledBattle(teams[j], teams[other], rule)
|
||||||
|
}
|
||||||
|
i += 1
|
||||||
|
gameCount = 0
|
||||||
|
for team in teams
|
||||||
|
gameCount += team.games
|
||||||
|
end
|
||||||
|
yield(nil)
|
||||||
|
if gameCount / teams.length >= 12
|
||||||
|
for team in teams
|
||||||
|
games = team.games
|
||||||
|
team.updateRating
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
teams.sort! { |a, b| b.rating <=> a.rating }
|
||||||
|
save_data(teams, tag + "teams.rxdata")
|
||||||
|
end
|
||||||
|
party = []
|
||||||
|
yield(nil)
|
||||||
|
teams.sort! { |a, b| a.rating <=> b.rating }
|
||||||
|
for team in teams
|
||||||
|
next if team.rating <= cutoffrating
|
||||||
|
for i in 0...team.length
|
||||||
|
party.push(team[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rule = oldrule
|
||||||
|
yield(nil)
|
||||||
|
party = pbRemoveDuplicates(party)
|
||||||
|
yield(_INTL("Writing results"))
|
||||||
|
party = pbArrangeByTier(party, rule)
|
||||||
|
yield(nil)
|
||||||
|
pbTrainerInfo(party, tag, rule) { yield(nil) }
|
||||||
|
yield(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbWriteCup(id, rules)
|
||||||
|
return if !$DEBUG
|
||||||
|
trlists = (load_data("Data/trainer_lists.dat") rescue [])
|
||||||
|
list = []
|
||||||
|
for i in 0...trlists.length
|
||||||
|
tr = trlists[i]
|
||||||
|
if tr[5]
|
||||||
|
list.push("*" + (tr[3].sub(/\.txt$/, "")))
|
||||||
|
else
|
||||||
|
list.push((tr[3].sub(/\.txt$/, "")))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
cmd = 0
|
||||||
|
if trlists.length != 0
|
||||||
|
cmd = pbMessage(_INTL("Generate Pokémon teams for this challenge?"),
|
||||||
|
[_INTL("NO"), _INTL("YES, USE EXISTING"), _INTL("YES, USE NEW")], 1)
|
||||||
|
else
|
||||||
|
cmd = pbMessage(_INTL("Generate Pokémon teams for this challenge?"),
|
||||||
|
[_INTL("YES"), _INTL("NO")], 2)
|
||||||
|
if cmd == 0
|
||||||
|
cmd = 2
|
||||||
|
elsif cmd == 1
|
||||||
|
cmd = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return if cmd == 0 # No
|
||||||
|
if cmd == 1 # Yes, use existing
|
||||||
|
cmd = pbMessage(_INTL("Choose a challenge."), list, -1)
|
||||||
|
if cmd >= 0
|
||||||
|
pbMessage(_INTL("This challenge will use the Pokémon list from {1}.", list[cmd]))
|
||||||
|
for i in 0...trlists.length
|
||||||
|
tr = trlists[i]
|
||||||
|
while !tr[5] && tr[2].include?(id)
|
||||||
|
tr[2].delete(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
trlists[cmd][2].push(id) if !trlists[cmd][5]
|
||||||
|
save_data(trlists, "Data/trainer_lists.dat")
|
||||||
|
Graphics.update
|
||||||
|
Compiler.write_trainer_lists
|
||||||
|
end
|
||||||
|
return
|
||||||
|
elsif cmd == 2 # Yes, use new
|
||||||
|
return if !pbConfirmMessage(_INTL("This may take a long time. Are you sure?"))
|
||||||
|
mw = pbCreateMessageWindow
|
||||||
|
t = Time.now
|
||||||
|
pbGenerateChallenge(rules, id) { |message|
|
||||||
|
if Time.now - t >= 5
|
||||||
|
Graphics.update
|
||||||
|
t = Time.now
|
||||||
|
end
|
||||||
|
if message
|
||||||
|
pbMessageDisplay(mw, message, false)
|
||||||
|
Graphics.update
|
||||||
|
t = Time.now
|
||||||
|
end
|
||||||
|
}
|
||||||
|
pbDisposeMessageWindow(mw)
|
||||||
|
pbMessage(_INTL("Team generation complete."))
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,366 @@
|
|||||||
|
$baseStatTotal = {}
|
||||||
|
$babySpecies = {}
|
||||||
|
$minimumLevel = {}
|
||||||
|
$evolutions = {}
|
||||||
|
$legalMoves = {} # For each species, all the moves they have access to
|
||||||
|
$legalMovesLevel = 0 # Level for which $legalMoves were calculated
|
||||||
|
$tmMoves = nil # Array of all moves teachable by a HM/TM/TR
|
||||||
|
|
||||||
|
def pbBaseStatTotal(species)
|
||||||
|
baseStats = GameData::Species.get(species).base_stats
|
||||||
|
ret = 0
|
||||||
|
baseStats.each { |s| ret += s }
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
|
||||||
|
def baseStatTotal(species)
|
||||||
|
$baseStatTotal[species] = pbBaseStatTotal(species) if !$baseStatTotal[species]
|
||||||
|
return $baseStatTotal[species]
|
||||||
|
end
|
||||||
|
|
||||||
|
def babySpecies(species)
|
||||||
|
$babySpecies[species] = GameData::Species.get(species).get_baby_species if !$babySpecies[species]
|
||||||
|
return $babySpecies[species]
|
||||||
|
end
|
||||||
|
|
||||||
|
def minimumLevel(species)
|
||||||
|
$minimumLevel[species] = GameData::Species.get(species).minimum_level if !$minimumLevel[species]
|
||||||
|
return $minimumLevel[species]
|
||||||
|
end
|
||||||
|
|
||||||
|
def evolutions(species)
|
||||||
|
$evolutions[species] = GameData::Species.get(species).get_evolutions(true) if !$evolutions[species]
|
||||||
|
return $evolutions[species]
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
# Used to replace Sketch with any other move.
|
||||||
|
def pbRandomMove
|
||||||
|
keys = GameData::Move::DATA.keys
|
||||||
|
loop do
|
||||||
|
move_id = keys[rand(keys.length)]
|
||||||
|
move = GameData::Move.get(move_id)
|
||||||
|
next if move.id_number > 384 || move.id == :SKETCH || move.id == :STRUGGLE
|
||||||
|
return move.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbGetLegalMoves2(species, maxlevel)
|
||||||
|
species_data = GameData::Species.get(species)
|
||||||
|
moves = []
|
||||||
|
return moves if !species_data
|
||||||
|
# Populate available moves array (moves)
|
||||||
|
species_data.moves.each { |m| addMove(moves, m[1], 2) if m[0] <= maxlevel }
|
||||||
|
if !$tmMoves
|
||||||
|
$tmMoves = []
|
||||||
|
GameData::Item.each { |i| $tmMoves.push(i.move) if i.is_machine? }
|
||||||
|
end
|
||||||
|
species_data.tutor_moves.each { |m| addMove(moves, m, 0) if $tmMoves.include?(m) }
|
||||||
|
babyspecies = babySpecies(species)
|
||||||
|
GameData::Species.get(babyspecies).egg_moves.each { |m| addMove(moves, m, 2) }
|
||||||
|
#
|
||||||
|
movedatas = []
|
||||||
|
for move in moves
|
||||||
|
movedatas.push([move, GameData::Move.get(move)])
|
||||||
|
end
|
||||||
|
# Delete less powerful moves
|
||||||
|
deleteAll = proc { |a, item|
|
||||||
|
while a.include?(item)
|
||||||
|
a.delete(item)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
for move in moves
|
||||||
|
md = GameData::Move.get(move)
|
||||||
|
for move2 in movedatas
|
||||||
|
# If we have a move that always hits, remove all other moves with no
|
||||||
|
# effect of the same type and <= base power
|
||||||
|
if md.function_code == "0A5" && move2[1].function_code == "000" && # Always hits
|
||||||
|
md.type == move2[1].type && md.base_damage >= move2[1].base_damage
|
||||||
|
deleteAll.call(moves, move2[0])
|
||||||
|
# If we have two status moves that have the same function code, delete the
|
||||||
|
# one with lower accuracy (Supersonic vs. Confuse Ray, etc.)
|
||||||
|
elsif md.function_code == move2[1].function_code && md.base_damage == 0 &&
|
||||||
|
move2[1].base_damage == 0 && md.accuracy > move2[1].accuracy
|
||||||
|
deleteAll.call(moves, move2[0])
|
||||||
|
# Delete poison-causing moves if we have a move that causes toxic
|
||||||
|
elsif md.function_code == "006" && move2[1].function_code == "005"
|
||||||
|
deleteAll.call(moves, move2[0])
|
||||||
|
# If we have two moves with the same function code and type, and one of
|
||||||
|
# them is damaging and has 10/15/the same PP as the other move and EITHER
|
||||||
|
# does more damage than the other move OR does the same damage but is more
|
||||||
|
# accurate, delete the other move (Surf, Flamethrower, Thunderbolt, etc.)
|
||||||
|
elsif md.function_code == move2[1].function_code && md.base_damage != 0 &&
|
||||||
|
md.type == move2[1].type &&
|
||||||
|
(md.total_pp == 15 || md.total_pp == 10 || md.total_pp == move2[1].total_pp) &&
|
||||||
|
(md.base_damage > move2[1].base_damage ||
|
||||||
|
(md.base_damage == move2[1].base_damage && md.accuracy > move2[1].accuracy))
|
||||||
|
deleteAll.call(moves, move2[0])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return moves
|
||||||
|
end
|
||||||
|
|
||||||
|
def addMove(moves, move, base)
|
||||||
|
data = GameData::Move.get(move)
|
||||||
|
return if moves.include?(data.id)
|
||||||
|
return if [:BUBBLE, :BUBBLEBEAM].include?(data.id) # Never add these moves
|
||||||
|
count = base + 1 # Number of times to add move to moves
|
||||||
|
count = base if data.function_code == "000" && data.base_damage <= 40
|
||||||
|
if data.base_damage <= 30 || [:GROWL, :TAILWHIP, :LEER].include?(data.id)
|
||||||
|
count = base
|
||||||
|
end
|
||||||
|
if data.base_damage >= 60 ||
|
||||||
|
[:REFLECT, :LIGHTSCREEN, :SAFEGUARD, :SUBSTITUTE, :FAKEOUT].include?(data.id)
|
||||||
|
count = base + 2
|
||||||
|
end
|
||||||
|
if data.base_damage >= 80 && data.type == :NORMAL
|
||||||
|
count = base + 3
|
||||||
|
end
|
||||||
|
if [:PROTECT, :DETECT, :TOXIC, :AERIALACE, :WILLOWISP, :SPORE, :THUNDERWAVE,
|
||||||
|
:HYPNOSIS, :CONFUSERAY, :ENDURE, :SWORDSDANCE].include?(data.id)
|
||||||
|
count = base + 3
|
||||||
|
end
|
||||||
|
count.times { moves.push(data.id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
# Returns whether moves contains any move with the same type as thismove but
|
||||||
|
# with a higher base damage than it.
|
||||||
|
def hasMorePowerfulMove(moves, thismove)
|
||||||
|
thisdata = GameData::Move.get(thismove)
|
||||||
|
return false if thisdata.base_damage == 0
|
||||||
|
for move in moves
|
||||||
|
next if !move
|
||||||
|
moveData = GameData::Move.get(move)
|
||||||
|
if moveData.type == thisdata.type && moveData.base_damage > thisdata.base_damage
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# Generate a random Pokémon that adheres to the given rules.
|
||||||
|
#===============================================================================
|
||||||
|
def pbRandomPokemonFromRule(rules, trainer)
|
||||||
|
pkmn = nil
|
||||||
|
iteration = -1
|
||||||
|
loop do
|
||||||
|
iteration += 1
|
||||||
|
species = nil
|
||||||
|
level = rules.ruleset.suggestedLevel
|
||||||
|
keys = GameData::Species::DATA.keys
|
||||||
|
loop do
|
||||||
|
loop do
|
||||||
|
species = keys[rand(keys.length)]
|
||||||
|
break if GameData::Species.get(species).form == 0
|
||||||
|
end
|
||||||
|
r = rand(20)
|
||||||
|
bst = baseStatTotal(species)
|
||||||
|
next if level < minimumLevel(species)
|
||||||
|
if iteration % 2 == 0
|
||||||
|
next if r < 16 && bst < 400
|
||||||
|
next if r < 13 && bst < 500
|
||||||
|
else
|
||||||
|
next if bst > 400
|
||||||
|
next if r < 10 && babySpecies(species) != species
|
||||||
|
end
|
||||||
|
next if r < 10 && babySpecies(species) == species
|
||||||
|
next if r < 7 && evolutions(species).length > 0
|
||||||
|
break
|
||||||
|
end
|
||||||
|
ev = []
|
||||||
|
GameData::Stat.each_main { |s| ev.push(s.id) if rand(100) < 50 }
|
||||||
|
nature = nil
|
||||||
|
keys = GameData::Nature::DATA.keys
|
||||||
|
loop do
|
||||||
|
nature = keys[rand(keys.length)]
|
||||||
|
nature_data = GameData::Nature.get(nature)
|
||||||
|
if [:LAX, :GENTLE].include?(nature_data.id) || nature_data.stat_changes.length == 0
|
||||||
|
next if rand(20) < 19
|
||||||
|
else
|
||||||
|
raised_emphasis = false
|
||||||
|
lowered_emphasis = false
|
||||||
|
nature_data.stat_changes.each do |change|
|
||||||
|
next if !ev.include?(change[0])
|
||||||
|
raised_emphasis = true if change[1] > 0
|
||||||
|
lowered_emphasis = true if change[1] < 0
|
||||||
|
end
|
||||||
|
next if rand(10) < 6 && !raised_emphasis
|
||||||
|
next if rand(10) < 9 && lowered_emphasis
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
$legalMoves = {} if level != $legalMovesLevel
|
||||||
|
$legalMovesLevel = level
|
||||||
|
$legalMoves[species] = pbGetLegalMoves2(species, level) if !$legalMoves[species]
|
||||||
|
itemlist = [
|
||||||
|
:ORANBERRY, :SITRUSBERRY, :ADAMANTORB, :BABIRIBERRY,
|
||||||
|
:BLACKSLUDGE, :BRIGHTPOWDER, :CHESTOBERRY, :CHOICEBAND,
|
||||||
|
:CHOICESCARF, :CHOICESPECS, :CHOPLEBERRY, :DAMPROCK,
|
||||||
|
:DEEPSEATOOTH, :EXPERTBELT, :FLAMEORB, :FOCUSSASH,
|
||||||
|
:FOCUSBAND, :HEATROCK, :LEFTOVERS, :LIFEORB, :LIGHTBALL,
|
||||||
|
:LIGHTCLAY, :LUMBERRY, :OCCABERRY, :PETAYABERRY, :SALACBERRY,
|
||||||
|
:SCOPELENS, :SHEDSHELL, :SHELLBELL, :SHUCABERRY, :LIECHIBERRY,
|
||||||
|
:SILKSCARF, :THICKCLUB, :TOXICORB, :WIDELENS, :YACHEBERRY,
|
||||||
|
:HABANBERRY, :SOULDEW, :PASSHOBERRY, :QUICKCLAW, :WHITEHERB
|
||||||
|
]
|
||||||
|
# Most used: Leftovers, Life Orb, Choice Band, Choice Scarf, Focus Sash
|
||||||
|
item = nil
|
||||||
|
loop do
|
||||||
|
if rand(40) == 0
|
||||||
|
item = :LEFTOVERS
|
||||||
|
break
|
||||||
|
end
|
||||||
|
item = itemlist[rand(itemlist.length)]
|
||||||
|
next if !item
|
||||||
|
case item
|
||||||
|
when :LIGHTBALL
|
||||||
|
next if species != :PIKACHU
|
||||||
|
when :SHEDSHELL
|
||||||
|
next if species != :FORRETRESS && species != :SKARMORY
|
||||||
|
when :SOULDEW
|
||||||
|
next if species != :LATIOS && species != :LATIAS
|
||||||
|
when :FOCUSSASH
|
||||||
|
next if baseStatTotal(species) > 450 && rand(10) < 8
|
||||||
|
when :ADAMANTORB
|
||||||
|
next if species != :DIALGA
|
||||||
|
when :PASSHOBERRY
|
||||||
|
next if species != :STEELIX
|
||||||
|
when :BABIRIBERRY
|
||||||
|
next if species != :TYRANITAR
|
||||||
|
when :HABANBERRY
|
||||||
|
next if species != :GARCHOMP
|
||||||
|
when :OCCABERRY
|
||||||
|
next if species != :METAGROSS
|
||||||
|
when :CHOPLEBERRY
|
||||||
|
next if species != :UMBREON
|
||||||
|
when :YACHEBERRY
|
||||||
|
next if ![:TORTERRA, :GLISCOR, :DRAGONAIR].include?(species)
|
||||||
|
when :SHUCABERRY
|
||||||
|
next if species != :HEATRAN
|
||||||
|
when :DEEPSEATOOTH
|
||||||
|
next if species != :CLAMPERL
|
||||||
|
when :THICKCLUB
|
||||||
|
next if ![:CUBONE, :MAROWAK].include?(species)
|
||||||
|
when :LIECHIBERRY
|
||||||
|
ev.push(:ATTACK) if !ev.include?(:ATTACK) && rand(100) < 50
|
||||||
|
when :SALACBERRY
|
||||||
|
ev.push(:SPEED) if !ev.include?(:SPEED) && rand(100) < 50
|
||||||
|
when :PETAYABERRY
|
||||||
|
ev.push(:SPECIAL_ATTACK) if !ev.include?(:SPECIAL_ATTACK) && rand(100) < 50
|
||||||
|
end
|
||||||
|
break
|
||||||
|
end
|
||||||
|
if level < 10 && GameData::Item.exists?(:ORANBERRY)
|
||||||
|
item = :ORANBERRY if rand(40) == 0 || item == :SITRUSBERRY
|
||||||
|
elsif level > 20 && GameData::Item.exists?(:SITRUSBERRY)
|
||||||
|
item = :SITRUSBERRY if rand(40) == 0 || item == :ORANBERRY
|
||||||
|
end
|
||||||
|
moves = $legalMoves[species]
|
||||||
|
sketch = false
|
||||||
|
if moves[0] == :SKETCH
|
||||||
|
sketch = true
|
||||||
|
for m in 0...Pokemon::MAX_MOVES
|
||||||
|
moves[m] = pbRandomMove
|
||||||
|
end
|
||||||
|
end
|
||||||
|
next if moves.length == 0
|
||||||
|
if (moves | []).length < Pokemon::MAX_MOVES
|
||||||
|
moves = [:TACKLE] if moves.length == 0
|
||||||
|
moves |= []
|
||||||
|
else
|
||||||
|
newmoves = []
|
||||||
|
rest = GameData::Move.exists?(:REST) ? :REST : nil
|
||||||
|
spitup = GameData::Move.exists?(:SPITUP) ? :SPITUP : nil
|
||||||
|
swallow = GameData::Move.exists?(:SWALLOW) ? :SWALLOW : nil
|
||||||
|
stockpile = GameData::Move.exists?(:STOCKPILE) ? :STOCKPILE : nil
|
||||||
|
snore = GameData::Move.exists?(:SNORE) ? :SNORE : nil
|
||||||
|
sleeptalk = GameData::Move.exists?(:SLEEPTALK) ? :SLEEPTALK : nil
|
||||||
|
loop do
|
||||||
|
newmoves.clear
|
||||||
|
while newmoves.length < [moves.length, Pokemon::MAX_MOVES].min
|
||||||
|
m = moves[rand(moves.length)]
|
||||||
|
next if rand(100) < 50 && hasMorePowerfulMove(moves, m)
|
||||||
|
newmoves.push(m) if m && !newmoves.include?(m)
|
||||||
|
end
|
||||||
|
if (newmoves.include?(spitup) || newmoves.include?(swallow)) &&
|
||||||
|
!newmoves.include?(stockpile)
|
||||||
|
next unless sketch
|
||||||
|
end
|
||||||
|
if (!newmoves.include?(spitup) && !newmoves.include?(swallow)) &&
|
||||||
|
newmoves.include?(stockpile)
|
||||||
|
next unless sketch
|
||||||
|
end
|
||||||
|
if newmoves.include?(sleeptalk) && !newmoves.include?(rest)
|
||||||
|
next unless (sketch || !moves.include?(rest)) && rand(100) < 20
|
||||||
|
end
|
||||||
|
if newmoves.include?(snore) && !newmoves.include?(rest)
|
||||||
|
next unless (sketch || !moves.include?(rest)) && rand(100) < 20
|
||||||
|
end
|
||||||
|
totalbasedamage = 0
|
||||||
|
hasPhysical = false
|
||||||
|
hasSpecial = false
|
||||||
|
hasNormal = false
|
||||||
|
for move in newmoves
|
||||||
|
d = GameData::Move.get(move)
|
||||||
|
if d.base_damage >= 1
|
||||||
|
totalbasedamage += d.base_damage
|
||||||
|
hasNormal = true if d.type == :NORMAL
|
||||||
|
hasPhysical = true if d.category == 0
|
||||||
|
hasSpecial = true if d.category == 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if !hasPhysical && ev.include?(:ATTACK)
|
||||||
|
# No physical attack, but emphasizes Attack
|
||||||
|
next if rand(100) < 80
|
||||||
|
end
|
||||||
|
if !hasSpecial && ev.include?(:SPECIAL_ATTACK)
|
||||||
|
# No special attack, but emphasizes Special Attack
|
||||||
|
next if rand(100) < 80
|
||||||
|
end
|
||||||
|
r = rand(10)
|
||||||
|
next if r > 6 && totalbasedamage > 180
|
||||||
|
next if r > 8 && totalbasedamage > 140
|
||||||
|
next if totalbasedamage == 0 && rand(100) < 95
|
||||||
|
############
|
||||||
|
# Moves accepted
|
||||||
|
if hasPhysical && !hasSpecial
|
||||||
|
ev.push(:ATTACK) if rand(100) < 80
|
||||||
|
ev.delete(:SPECIAL_ATTACK) if rand(100) < 80
|
||||||
|
end
|
||||||
|
if !hasPhysical && hasSpecial
|
||||||
|
ev.delete(:ATTACK) if rand(100) < 80
|
||||||
|
ev.push(:SPECIAL_ATTACK) if rand(100) < 80
|
||||||
|
end
|
||||||
|
item = :LEFTOVERS if !hasNormal && item == :SILKSCARF
|
||||||
|
moves = newmoves
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if item == :LIGHTCLAY && !moves.any? { |m| m == :LIGHTSCREEN || m = :REFLECT }
|
||||||
|
item = :LEFTOVERS
|
||||||
|
end
|
||||||
|
if item == :BLACKSLUDGE
|
||||||
|
type1 = GameData::Species.get(species).type1
|
||||||
|
type2 = GameData::Species.get(species).type2 || type1
|
||||||
|
item = :LEFTOVERS if type1 != :POISON && type2 != :POISON
|
||||||
|
end
|
||||||
|
if item == :HEATROCK && !moves.any? { |m| m == :SUNNYDAY }
|
||||||
|
item = :LEFTOVERS
|
||||||
|
end
|
||||||
|
if item == :DAMPROCK && !moves.any? { |m| m == :RAINDANCE }
|
||||||
|
item = :LEFTOVERS
|
||||||
|
end
|
||||||
|
if moves.any? { |m| m == :REST }
|
||||||
|
item = :LUMBERRY if rand(100) < 33
|
||||||
|
item = :CHESTOBERRY if rand(100) < 25
|
||||||
|
end
|
||||||
|
pk = PBPokemon.new(species, item, nature, moves[0], moves[1], moves[2], moves[3], ev)
|
||||||
|
pkmn = pk.createPokemon(level, 31, trainer)
|
||||||
|
break if rules.ruleset.isPokemonValid?(pkmn)
|
||||||
|
end
|
||||||
|
return pkmn
|
||||||
|
end
|
||||||
@@ -0,0 +1,215 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def getTypes(species)
|
||||||
|
species_data = GameData::Species.get(species)
|
||||||
|
type1 = species_data.type1
|
||||||
|
type2 = species_data.type2
|
||||||
|
return (type1 == type2) ? [type1] : [type1, type2]
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
# If no trainers are defined for the current challenge, generate a set of random
|
||||||
|
# ones for it. If pokemonlist is given, assign Pokémon from it to all trainers.
|
||||||
|
# Save the results in the appropriate PBS files.
|
||||||
|
#===============================================================================
|
||||||
|
def pbTrainerInfo(pokemonlist, trfile, rules)
|
||||||
|
bttrainers = pbGetBTTrainers(trfile)
|
||||||
|
btpokemon = pbGetBTPokemon(trfile)
|
||||||
|
# No battle trainers found; fill bttrainers with 200 randomly chosen ones from
|
||||||
|
# all that exist (with a base money < 100)
|
||||||
|
if bttrainers.length == 0
|
||||||
|
for i in 0...200
|
||||||
|
yield(nil) if block_given? && i % 50 == 0
|
||||||
|
trainerid = nil
|
||||||
|
if GameData::TrainerType.exists?(:YOUNGSTER) && rand(30) == 0
|
||||||
|
trainerid = :YOUNGSTER
|
||||||
|
else
|
||||||
|
tr_typekeys = GameData::TrainerType::DATA.keys
|
||||||
|
loop do
|
||||||
|
tr_type = tr_typekeys[rand(tr_typekeys.length)]
|
||||||
|
tr_type_data = GameData::TrainerType.get(tr_type)
|
||||||
|
next if tr_type_data.base_money >= 100
|
||||||
|
trainerid = tr_type_data.id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# Create a random name for the trainer
|
||||||
|
gender = GameData::TrainerType.get(trainerid).gender
|
||||||
|
randomName = getRandomNameEx(gender, nil, 0, 12)
|
||||||
|
# Add the trainer to bttrainers
|
||||||
|
tr = [trainerid, randomName, _INTL("Here I come!"), _INTL("Yes, I won!"),
|
||||||
|
_INTL("Man, I lost!"), []]
|
||||||
|
bttrainers.push(tr)
|
||||||
|
end
|
||||||
|
# Sort all the randomly chosen trainers by their base money (smallest first)
|
||||||
|
bttrainers.sort! { |a, b|
|
||||||
|
money1 = GameData::TrainerType.get(a[0]).base_money
|
||||||
|
money2 = GameData::TrainerType.get(b[0]).base_money
|
||||||
|
next (money1 == money2) ? a[0].to_s <=> b[0].to_s : money1 <=> money2
|
||||||
|
}
|
||||||
|
end
|
||||||
|
yield(nil) if block_given?
|
||||||
|
# Set all Pokémon in pokemonlist to the appropriate level, and determine their
|
||||||
|
# type(s) and whether they are valid for the given rules
|
||||||
|
suggestedLevel = rules.ruleset.suggestedLevel
|
||||||
|
rulesetTeam = rules.ruleset.copy.clearPokemonRules
|
||||||
|
pkmntypes = []
|
||||||
|
validities = []
|
||||||
|
for pkmn in pokemonlist
|
||||||
|
pkmn.level = suggestedLevel if pkmn.level != suggestedLevel
|
||||||
|
pkmntypes.push(getTypes(pkmn.species))
|
||||||
|
validities.push(rules.ruleset.isPokemonValid?(pkmn))
|
||||||
|
end
|
||||||
|
# For each trainer in bttrainers, come up with a set of Pokémon taken from
|
||||||
|
# pokemonlist for that trainer, and copy the trainer and their set of Pokémon
|
||||||
|
# to newbttrainers
|
||||||
|
newbttrainers = []
|
||||||
|
for btt in 0...bttrainers.length
|
||||||
|
yield(nil) if block_given? && btt % 50 == 0
|
||||||
|
trainerdata = bttrainers[btt]
|
||||||
|
pokemonnumbers = trainerdata[5] || []
|
||||||
|
# Find all the Pokémon available to the trainer, and count up how often
|
||||||
|
# those Pokémon have each type
|
||||||
|
species = []
|
||||||
|
types = {}
|
||||||
|
GameData::Type.each { |t| types[t.id] = 0 }
|
||||||
|
for pn in pokemonnumbers
|
||||||
|
pkmn = btpokemon[pn]
|
||||||
|
species.push(pkmn.species)
|
||||||
|
t = getTypes(pkmn.species)
|
||||||
|
t.each { |typ| types[typ] += 1 }
|
||||||
|
end
|
||||||
|
species |= [] # remove duplicates
|
||||||
|
# Scale down the counts of each type to the range 0 -> 10
|
||||||
|
count = 0
|
||||||
|
GameData::Type.each do |t|
|
||||||
|
if types[t.id] >= 5
|
||||||
|
types[t.id] /= 4
|
||||||
|
types[t.id] = 10 if types[t.id] > 10
|
||||||
|
else
|
||||||
|
types[t.id] = 0
|
||||||
|
end
|
||||||
|
count += types[t.id]
|
||||||
|
end
|
||||||
|
types[:NORMAL] = 1 if count == 0 # All type counts are 0; add 1 to Normal
|
||||||
|
# Trainer had no Pokémon available to it; make all the type counts 1
|
||||||
|
if pokemonnumbers.length == 0
|
||||||
|
GameData::Type.each { |t| types[t.id] = 1 }
|
||||||
|
end
|
||||||
|
# Get Pokémon from pokemonlist, if there are any, and make sure enough are
|
||||||
|
# gotten that a valid team can be made from them
|
||||||
|
numbers = []
|
||||||
|
if pokemonlist
|
||||||
|
# For each valid Pokémon in pokemonlist, add its index within pokemonlist
|
||||||
|
# to numbers, but only if that species is available to the trainer.
|
||||||
|
# Pokémon are less likely to be added if it is positioned later in
|
||||||
|
# pokemonlist, or if the trainer is positioned earlier in bttrainers (i.e.
|
||||||
|
# later trainers get better Pokémon).
|
||||||
|
numbersPokemon = []
|
||||||
|
for index in 0...pokemonlist.length
|
||||||
|
next if !validities[index]
|
||||||
|
pkmn = pokemonlist[index]
|
||||||
|
absDiff = ((index * 8 / pokemonlist.length) - (btt * 8 / bttrainers.length)).abs
|
||||||
|
if species.include?(pkmn.species)
|
||||||
|
weight = [32, 12, 5, 2, 1, 0, 0, 0][[absDiff, 7].min]
|
||||||
|
if rand(40) < weight
|
||||||
|
numbers.push(index)
|
||||||
|
numbersPokemon.push(pokemonlist[index])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
# Pokémon's species isn't available to the trainer; try adding it
|
||||||
|
# anyway (more likely to add it if the trainer has access to more
|
||||||
|
# Pokémon of the same type(s) as this Pokémon)
|
||||||
|
t = pkmntypes[index]
|
||||||
|
t.each { |typ|
|
||||||
|
weight = [32, 12, 5, 2, 1, 0, 0, 0][[absDiff, 7].min]
|
||||||
|
weight *= types[typ]
|
||||||
|
if rand(40) < weight
|
||||||
|
numbers.push(index)
|
||||||
|
numbersPokemon.push(pokemonlist[index])
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
numbers |= [] # Remove duplicates
|
||||||
|
# If there aren't enough Pokémon to form a full team, or a valid team
|
||||||
|
# can't be made from them, fill up numbers with Pokémon in pokemonlist
|
||||||
|
# that EITHER have the same species as one available to the trainer OR has
|
||||||
|
# a type that is available to the trainer, until a valid team can be
|
||||||
|
# formed from what's in numbers
|
||||||
|
if numbers.length < Settings::MAX_PARTY_SIZE ||
|
||||||
|
!rulesetTeam.hasValidTeam?(numbersPokemon)
|
||||||
|
for index in 0...pokemonlist.length
|
||||||
|
pkmn = pokemonlist[index]
|
||||||
|
next if !validities[index]
|
||||||
|
if species.include?(pkmn.species)
|
||||||
|
numbers.push(index)
|
||||||
|
numbersPokemon.push(pokemonlist[index])
|
||||||
|
else
|
||||||
|
t = pkmntypes[index]
|
||||||
|
t.each { |typ|
|
||||||
|
if types[typ] > 0 && !numbers.include?(index)
|
||||||
|
numbers.push(index)
|
||||||
|
numbersPokemon.push(pokemonlist[index])
|
||||||
|
break
|
||||||
|
end
|
||||||
|
}
|
||||||
|
end
|
||||||
|
break if numbers.length >= Settings::MAX_PARTY_SIZE && rules.ruleset.hasValidTeam?(numbersPokemon)
|
||||||
|
end
|
||||||
|
# If there STILL aren't enough Pokémon to form a full team, or a valid
|
||||||
|
# team can't be made from them, add random Pokémon from pokemonlist
|
||||||
|
# until a valid team can be formed from what's in numbers
|
||||||
|
if numbers.length < Settings::MAX_PARTY_SIZE || !rules.ruleset.hasValidTeam?(numbersPokemon)
|
||||||
|
while numbers.length < pokemonlist.length &&
|
||||||
|
(numbers.length < Settings::MAX_PARTY_SIZE || !rules.ruleset.hasValidTeam?(numbersPokemon))
|
||||||
|
index = rand(pokemonlist.length)
|
||||||
|
if !numbers.include?(index)
|
||||||
|
numbers.push(index)
|
||||||
|
numbersPokemon.push(pokemonlist[index])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
numbers.sort!
|
||||||
|
end
|
||||||
|
# Add the trainer's data, including all Pokémon that should be available to
|
||||||
|
# it (from pokemonlist), to newbttrainers
|
||||||
|
newbttrainers.push([trainerdata[0], trainerdata[1], trainerdata[2],
|
||||||
|
trainerdata[3], trainerdata[4], numbers])
|
||||||
|
end
|
||||||
|
yield(nil) if block_given?
|
||||||
|
# Add the trainer and Pokémon data from above to trainer_lists.dat, and then
|
||||||
|
# create all PBS files from it
|
||||||
|
pbpokemonlist = []
|
||||||
|
for pkmn in pokemonlist
|
||||||
|
pbpokemonlist.push(PBPokemon.fromPokemon(pkmn))
|
||||||
|
end
|
||||||
|
trlists = (load_data("Data/trainer_lists.dat") rescue [])
|
||||||
|
hasDefault = false
|
||||||
|
trIndex = -1
|
||||||
|
for i in 0...trlists.length
|
||||||
|
next if !trlists[i][5]
|
||||||
|
hasDefault = true
|
||||||
|
break
|
||||||
|
end
|
||||||
|
for i in 0...trlists.length
|
||||||
|
if trlists[i][2].include?(trfile)
|
||||||
|
trIndex = i
|
||||||
|
trlists[i][0] = newbttrainers
|
||||||
|
trlists[i][1] = pbpokemonlist
|
||||||
|
trlists[i][5] = !hasDefault
|
||||||
|
end
|
||||||
|
end
|
||||||
|
yield(nil) if block_given?
|
||||||
|
if trIndex < 0
|
||||||
|
info = [newbttrainers, pbpokemonlist, [trfile],
|
||||||
|
trfile + "tr.txt", trfile + "pm.txt", !hasDefault]
|
||||||
|
trlists.push(info)
|
||||||
|
end
|
||||||
|
yield(nil) if block_given?
|
||||||
|
save_data(trlists, "Data/trainer_lists.dat")
|
||||||
|
yield(nil) if block_given?
|
||||||
|
Compiler.write_trainer_lists
|
||||||
|
yield(nil) if block_given?
|
||||||
|
end
|
||||||
@@ -0,0 +1,433 @@
|
|||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class RuledTeam
|
||||||
|
attr_accessor :team
|
||||||
|
|
||||||
|
def initialize(party, rule)
|
||||||
|
count = rule.ruleset.suggestedNumber
|
||||||
|
@team = []
|
||||||
|
retnum = []
|
||||||
|
loop do
|
||||||
|
for i in 0...count
|
||||||
|
retnum[i] = rand(party.length)
|
||||||
|
@team[i] = party[retnum[i]]
|
||||||
|
party.delete_at(retnum[i])
|
||||||
|
end
|
||||||
|
break if rule.ruleset.isValid?(@team)
|
||||||
|
end
|
||||||
|
@totalGames = 0
|
||||||
|
@rating = PlayerRating.new
|
||||||
|
@history = MatchHistory.new(@rating)
|
||||||
|
end
|
||||||
|
|
||||||
|
def [](i)
|
||||||
|
@team[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
def length
|
||||||
|
return @team.length
|
||||||
|
end
|
||||||
|
|
||||||
|
def rating
|
||||||
|
@rating.winChancePercent
|
||||||
|
end
|
||||||
|
|
||||||
|
def ratingData
|
||||||
|
@rating
|
||||||
|
end
|
||||||
|
|
||||||
|
def ratingRaw
|
||||||
|
[@rating.rating, @rating.deviation, @rating.volatility, @rating.winChancePercent]
|
||||||
|
end
|
||||||
|
|
||||||
|
def compare(other)
|
||||||
|
@rating.compare(other.ratingData)
|
||||||
|
end
|
||||||
|
|
||||||
|
def totalGames
|
||||||
|
(@totalGames || 0) + self.games
|
||||||
|
end
|
||||||
|
|
||||||
|
def addMatch(other,score)
|
||||||
|
@history.addMatch(other.ratingData, score)
|
||||||
|
end
|
||||||
|
|
||||||
|
def games
|
||||||
|
@history.length
|
||||||
|
end
|
||||||
|
|
||||||
|
def updateRating
|
||||||
|
@totalGames = 0 if !@totalGames
|
||||||
|
oldgames = self.games
|
||||||
|
@history.updateAndClear()
|
||||||
|
newgames = self.games
|
||||||
|
@totalGames += (oldgames - newgames)
|
||||||
|
end
|
||||||
|
|
||||||
|
def toStr
|
||||||
|
return "[" + @rating.to_i.to_s + "," + @games.to_i.to_s + "]"
|
||||||
|
end
|
||||||
|
|
||||||
|
def load(party)
|
||||||
|
ret = []
|
||||||
|
for i in 0...team.length
|
||||||
|
ret.push(party[team[i]])
|
||||||
|
end
|
||||||
|
return ret
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class SingleMatch
|
||||||
|
attr_reader :opponentRating
|
||||||
|
attr_reader :opponentDeviation
|
||||||
|
attr_reader :score
|
||||||
|
attr_reader :kValue
|
||||||
|
|
||||||
|
def initialize(opponentRating, opponentDev, score, kValue = 16)
|
||||||
|
@opponentRating = opponentRating
|
||||||
|
@opponentDeviation = opponentDev
|
||||||
|
@score = score # -1=draw, 0=lose, 1=win
|
||||||
|
@kValue = kValue
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class MatchHistory
|
||||||
|
include Enumerable
|
||||||
|
|
||||||
|
def initialize(thisPlayer)
|
||||||
|
@matches = []
|
||||||
|
@thisPlayer = thisPlayer
|
||||||
|
end
|
||||||
|
|
||||||
|
def [](i)
|
||||||
|
@matches[i]
|
||||||
|
end
|
||||||
|
|
||||||
|
def length
|
||||||
|
@matches.length
|
||||||
|
end
|
||||||
|
|
||||||
|
def each
|
||||||
|
@matches.each { |item| yield item }
|
||||||
|
end
|
||||||
|
|
||||||
|
def addMatch(otherPlayer, result)
|
||||||
|
# 1=I won; 0=Other player won; -1: Draw
|
||||||
|
@matches.push(SingleMatch.new(otherPlayer.rating, otherPlayer.deviation, result))
|
||||||
|
end
|
||||||
|
|
||||||
|
def updateAndClear
|
||||||
|
@thisPlayer.update(@matches)
|
||||||
|
@matches.clear
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class PlayerRatingElo
|
||||||
|
attr_reader :rating
|
||||||
|
K_VALUE = 16
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@rating = 1600.0
|
||||||
|
@deviation = 0
|
||||||
|
@volatility = 0
|
||||||
|
@estimatedRating = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def winChancePercent
|
||||||
|
return @estimatedRating if @estimatedRating
|
||||||
|
x = (1 + 10.0**((@rating - 1600.0) / 400.0))
|
||||||
|
@estimatedRating = (x == 0 ? 1.0 : 1.0 / x)
|
||||||
|
return @estimatedRating
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(matches)
|
||||||
|
return if matches.length == 0
|
||||||
|
stake = 0
|
||||||
|
matches.length.times do
|
||||||
|
score = (match.score == -1) ? 0.5 : match.score
|
||||||
|
e = (1 + 10.0**((@rating - match.opponentRating) / 400.0))
|
||||||
|
stake += match.kValue * (score - e)
|
||||||
|
end
|
||||||
|
@rating += stake
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
class PlayerRating
|
||||||
|
attr_reader :volatility
|
||||||
|
attr_reader :deviation
|
||||||
|
attr_reader :rating
|
||||||
|
|
||||||
|
def initialize
|
||||||
|
@rating = 1500.0
|
||||||
|
@deviation = 350.0
|
||||||
|
@volatility = 0.9
|
||||||
|
@estimatedRating = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def winChancePercent
|
||||||
|
return @estimatedRating if @estimatedRating
|
||||||
|
if @deviation > 100
|
||||||
|
# https://www.smogon.com/forums/threads/make-sense-of-your-shoddy-battle-rating.55764/
|
||||||
|
otherRating = 1500.0
|
||||||
|
otherDeviation = 350.0
|
||||||
|
s = Math.sqrt(100000.0 + @deviation * @deviation + otherDeviation * otherDeviation)
|
||||||
|
g = 10.0**((otherRating - @rating) * 0.79 / s)
|
||||||
|
@estimatedRating = (1.0 / (1.0 + g)) * 100.0 # Percent chance that I win against opponent
|
||||||
|
else
|
||||||
|
# GLIXARE method
|
||||||
|
rds = @deviation * @deviation
|
||||||
|
sqr = Math.sqrt(15.905694331435 * (rds + 221781.21786254))
|
||||||
|
inner = (1500.0 - @rating) * Math::PI / sqr
|
||||||
|
@estimatedRating = (10000.0 / (1.0 + (10.0**inner)) + 0.5) / 100.0
|
||||||
|
end
|
||||||
|
return @estimatedRating
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(matches, system = 1.2)
|
||||||
|
volatility = volatility2
|
||||||
|
deviation = deviation2
|
||||||
|
rating = rating2
|
||||||
|
if matches.length == 0
|
||||||
|
setDeviation2(Math.sqrt(deviation * deviation + volatility * volatility))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
g = []
|
||||||
|
e = []
|
||||||
|
score = []
|
||||||
|
for i in 0...matches.length
|
||||||
|
match = matches[i]
|
||||||
|
g[i] = getGFactor(match.opponentDeviation)
|
||||||
|
e[i] = getEFactor(rating, match.opponentRating, g[i])
|
||||||
|
score[i] = match.score
|
||||||
|
end
|
||||||
|
# Estimated variance
|
||||||
|
variance = 0.0
|
||||||
|
for i in 0...matches.length
|
||||||
|
variance += g[i] * g[i] * e[i] * (1 - e[i])
|
||||||
|
end
|
||||||
|
variance = 1.0 / variance
|
||||||
|
# Improvement sum
|
||||||
|
sum = 0.0
|
||||||
|
for i in 0...matches.length
|
||||||
|
v = score[i]
|
||||||
|
sum += g[i] * (v.to_f - e[i]) if v != -1
|
||||||
|
end
|
||||||
|
volatility = getUpdatedVolatility(volatility, deviation, variance, sum, system)
|
||||||
|
# Update deviation
|
||||||
|
t = deviation * deviation + volatility * volatility
|
||||||
|
deviation = 1.0 / Math.sqrt(1.0 / t + 1.0 / variance)
|
||||||
|
# Update rating
|
||||||
|
rating = rating + deviation * deviation * sum
|
||||||
|
setRating2(rating)
|
||||||
|
setDeviation2(deviation)
|
||||||
|
setVolatility2(volatility)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
attr_writer :volatility
|
||||||
|
|
||||||
|
alias volatility2 volatility
|
||||||
|
|
||||||
|
def rating2
|
||||||
|
return (@rating - 1500.0) / 173.7178
|
||||||
|
end
|
||||||
|
|
||||||
|
def deviation2
|
||||||
|
return @deviation / 173.7178
|
||||||
|
end
|
||||||
|
|
||||||
|
def getGFactor(deviation)
|
||||||
|
# deviation is not yet in glicko2
|
||||||
|
deviation /= 173.7178
|
||||||
|
return 1.0 / Math.sqrt(1.0 + (3.0 * deviation * deviation) / (Math::PI * Math::PI))
|
||||||
|
end
|
||||||
|
|
||||||
|
def getEFactor(rating, opponentRating, g)
|
||||||
|
# rating is already in glicko2
|
||||||
|
# opponentRating is not yet in glicko2
|
||||||
|
opponentRating = (opponentRating - 1500.0) / 173.7178
|
||||||
|
return 1.0 / (1.0 + Math.exp(-g * (rating - opponentRating)))
|
||||||
|
end
|
||||||
|
|
||||||
|
def setVolatility2(value)
|
||||||
|
@volatility = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def setRating2(value)
|
||||||
|
@estimatedRating = nil
|
||||||
|
@rating = (value * 173.7178) + 1500.0
|
||||||
|
end
|
||||||
|
|
||||||
|
def setDeviation2(value)
|
||||||
|
@estimatedRating = nil
|
||||||
|
@deviation = value * 173.7178
|
||||||
|
end
|
||||||
|
|
||||||
|
def getUpdatedVolatility(volatility, deviation, variance, improvementSum, system)
|
||||||
|
improvement = improvementSum * variance
|
||||||
|
a = Math.log(volatility * volatility)
|
||||||
|
squSystem = system * system
|
||||||
|
squDeviation = deviation * deviation
|
||||||
|
squVariance = variance + variance
|
||||||
|
squDevplusVar = squDeviation + variance
|
||||||
|
x0 = a
|
||||||
|
100.times { # Up to 100 iterations to avoid potentially infinite loops
|
||||||
|
e = Math.exp(x0)
|
||||||
|
d = squDevplusVar + e
|
||||||
|
squD = d * d
|
||||||
|
i = improvement / d
|
||||||
|
h1 = -(x0 - a) / squSystem - 0.5 * e * i * i
|
||||||
|
h2 = -1.0 / squSystem - 0.5 * e * squDevplusVar / squD
|
||||||
|
h2 += 0.5 * squVariance * e * (squDevplusVar - e) / (squD * d)
|
||||||
|
x1 = x0
|
||||||
|
x0 -= h1 / h2
|
||||||
|
break if ((x1 - x0).abs < 0.000001)
|
||||||
|
}
|
||||||
|
return Math.exp(x0 / 2.0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbDecideWinnerEffectiveness(move, otype1, otype2, ability, scores)
|
||||||
|
data = GameData::Move.get(move)
|
||||||
|
return 0 if data.base_damage == 0
|
||||||
|
atype = data.type
|
||||||
|
typemod = Effectiveness::NORMAL_EFFECTIVE_ONE ** 2
|
||||||
|
if ability != :LEVITATE || data.type != :GROUND
|
||||||
|
mod1 = Effectiveness.calculate_one(atype, otype1)
|
||||||
|
mod2 = (otype1 == otype2) ? Effectiveness::NORMAL_EFFECTIVE_ONE : Effectiveness.calculate_one(atype, otype2)
|
||||||
|
if ability == :WONDERGUARD
|
||||||
|
mod1 = Effectiveness::NORMAL_EFFECTIVE_ONE if mod1 <= Effectiveness::NORMAL_EFFECTIVE_ONE
|
||||||
|
mod2 = Effectiveness::NORMAL_EFFECTIVE_ONE if mod2 <= Effectiveness::NORMAL_EFFECTIVE_ONE
|
||||||
|
end
|
||||||
|
typemod = mod1 * mod2
|
||||||
|
end
|
||||||
|
return scores[0] if typemod == 0 # Ineffective
|
||||||
|
return scores[1] if typemod == 1 # Doubly not very effective
|
||||||
|
return scores[2] if typemod == 2 # Not very effective
|
||||||
|
return scores[3] if typemod == 4 # Normal effective
|
||||||
|
return scores[4] if typemod == 8 # Super effective
|
||||||
|
return scores[5] if typemod == 16 # Doubly super effective
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbDecideWinnerScore(party0, party1, rating)
|
||||||
|
score = 0
|
||||||
|
types1 = []
|
||||||
|
types2 = []
|
||||||
|
abilities = []
|
||||||
|
for j in 0...party1.length
|
||||||
|
types1.push(party1[j].type1)
|
||||||
|
types2.push(party1[j].type2)
|
||||||
|
abilities.push(party1[j].ability_id)
|
||||||
|
end
|
||||||
|
for i in 0...party0.length
|
||||||
|
for move in party0[i].moves
|
||||||
|
next if !move
|
||||||
|
for j in 0...party1.length
|
||||||
|
score += pbDecideWinnerEffectiveness(move.id,
|
||||||
|
types1[j], types2[j], abilities[j], [-16, -8, 0, 4, 12, 20])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
basestatsum = baseStatTotal(party0[i].species)
|
||||||
|
score += basestatsum / 10
|
||||||
|
score += 10 if party0[i].item # Not in Battle Dome ranking
|
||||||
|
end
|
||||||
|
score += rating + rand(32)
|
||||||
|
return score
|
||||||
|
end
|
||||||
|
|
||||||
|
def pbDecideWinner(party0, party1, rating0, rating1)
|
||||||
|
rating0 = (rating0 * 15.0 / 100).round
|
||||||
|
rating1 = (rating1 * 15.0 / 100).round
|
||||||
|
score0 = pbDecideWinnerScore(party0, party1, rating0)
|
||||||
|
score1 = pbDecideWinnerScore(party1, party0, rating1)
|
||||||
|
if score0 == score1
|
||||||
|
return 5 if rating0 == rating1
|
||||||
|
return (rating0 > rating1) ? 1 : 2
|
||||||
|
else
|
||||||
|
return (score0 > score1) ? 1 : 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#===============================================================================
|
||||||
|
#
|
||||||
|
#===============================================================================
|
||||||
|
def pbRuledBattle(team1, team2, rule)
|
||||||
|
decision = 0
|
||||||
|
if rand(100) != 0
|
||||||
|
party1 = []
|
||||||
|
party2 = []
|
||||||
|
team1.length.times { |i| party1.push(team1[i]) }
|
||||||
|
team2.length.times { |i| party2.push(team2[i]) }
|
||||||
|
decision = pbDecideWinner(party1, party2, team1.rating, team2.rating)
|
||||||
|
else
|
||||||
|
level = rule.ruleset.suggestedLevel
|
||||||
|
t_type = nil
|
||||||
|
GameData::TrainerType.each { |t| t_type = t.id; break }
|
||||||
|
trainer1 = NPCTrainer.new("PLAYER1", t_type)
|
||||||
|
trainer2 = NPCTrainer.new("PLAYER2", t_type)
|
||||||
|
items1 = []
|
||||||
|
items2 = []
|
||||||
|
team1.each_with_index do |p, i|
|
||||||
|
next if !p
|
||||||
|
if p.level != level
|
||||||
|
p.level = level
|
||||||
|
p.calc_stats
|
||||||
|
end
|
||||||
|
items1[i] = p.item_id
|
||||||
|
trainer1.party.push(p)
|
||||||
|
end
|
||||||
|
team2.each_with_index do |p, i|
|
||||||
|
next if !p
|
||||||
|
if p.level != level
|
||||||
|
p.level = level
|
||||||
|
p.calc_stats
|
||||||
|
end
|
||||||
|
items2[i] = p.item_id
|
||||||
|
trainer2.party.push(p)
|
||||||
|
end
|
||||||
|
scene = PokeBattle_DebugSceneNoLogging.new
|
||||||
|
battle = rule.createBattle(scene, trainer1, trainer2)
|
||||||
|
battle.debug = true
|
||||||
|
battle.controlPlayer = true
|
||||||
|
battle.internalBattle = false
|
||||||
|
decision = battle.pbStartBattle
|
||||||
|
team1.each_with_index do |p, i|
|
||||||
|
next if !p
|
||||||
|
p.heal
|
||||||
|
p.item = items1[i]
|
||||||
|
end
|
||||||
|
team2.each_with_index do |p, i|
|
||||||
|
next if !p
|
||||||
|
p.heal
|
||||||
|
p.item = items2[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if decision == 1 # Team 1 wins
|
||||||
|
team1.addMatch(team2, 1)
|
||||||
|
team2.addMatch(team1, 0)
|
||||||
|
elsif decision == 2 # Team 2 wins
|
||||||
|
team1.addMatch(team2, 0)
|
||||||
|
team2.addMatch(team1, 1)
|
||||||
|
else
|
||||||
|
team1.addMatch(team2, -1)
|
||||||
|
team2.addMatch(team1, -1)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,973 +0,0 @@
|
|||||||
#===============================================================================
|
|
||||||
# Pokémon Organized Battle
|
|
||||||
#===============================================================================
|
|
||||||
def pbHasEligible?(*arg)
|
|
||||||
return pbBattleChallenge.rules.ruleset.hasValidTeam?($Trainer.party)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PBPokemon
|
|
||||||
attr_accessor :species
|
|
||||||
attr_accessor :item
|
|
||||||
attr_accessor :nature
|
|
||||||
attr_accessor :move1
|
|
||||||
attr_accessor :move2
|
|
||||||
attr_accessor :move3
|
|
||||||
attr_accessor :move4
|
|
||||||
attr_accessor :ev
|
|
||||||
|
|
||||||
def initialize(species,item,nature,move1,move2,move3,move4,ev)
|
|
||||||
@species = species
|
|
||||||
itm = GameData::Item.try_get(item)
|
|
||||||
@item = itm ? itm.id : nil
|
|
||||||
@nature = nature
|
|
||||||
@move1 = move1 ? move1 : nil
|
|
||||||
@move2 = move2 ? move2 : nil
|
|
||||||
@move3 = move3 ? move3 : nil
|
|
||||||
@move4 = move4 ? move4 : nil
|
|
||||||
@ev = ev
|
|
||||||
end
|
|
||||||
|
|
||||||
# This method is how each Pokémon is compiled from the PBS files listing
|
|
||||||
# Battle Tower/Cup Pokémon.
|
|
||||||
def self.fromInspected(str)
|
|
||||||
insp=str.gsub(/^\s+/,"").gsub(/\s+$/,"")
|
|
||||||
pieces=insp.split(/\s*;\s*/)
|
|
||||||
species = (GameData::Species.exists?(pieces[0])) ? GameData::Species.get(pieces[0]).id : nil
|
|
||||||
item = (GameData::Item.exists?(pieces[1])) ? GameData::Item.get(pieces[1]).id : nil
|
|
||||||
nature = (GameData::Nature.exists?(pieces[2])) ? GameData::Nature.get(pieces[2]).id : nil
|
|
||||||
ev = pieces[3].split(/\s*,\s*/)
|
|
||||||
ev_array = []
|
|
||||||
ev.each do |stat|
|
|
||||||
case stat.upcase
|
|
||||||
when "HP" then ev_array.push(:HP)
|
|
||||||
when "ATK" then ev_array.push(:ATTACK)
|
|
||||||
when "DEF" then ev_array.push(:DEFENSE)
|
|
||||||
when "SA", "SPATK" then ev_array.push(:SPECIAL_ATTACK)
|
|
||||||
when "SD", "SPDEF" then ev_array.push(:SPECIAL_DEFENSE)
|
|
||||||
when "SPD" then ev_array.push(:SPEED)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
moves=pieces[4].split(/\s*,\s*/)
|
|
||||||
moveid=[]
|
|
||||||
for i in 0...Pokemon::MAX_MOVES
|
|
||||||
move_data = GameData::Move.try_get(moves[i])
|
|
||||||
moveid.push(move_data.id) if move_data
|
|
||||||
end
|
|
||||||
if moveid.length==0
|
|
||||||
GameData::Move.each { |mov| moveid.push(mov.id); break }
|
|
||||||
end
|
|
||||||
return self.new(species, item, nature, moveid[0], moveid[1], moveid[2], moveid[3], ev_array)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.fromPokemon(pokemon)
|
|
||||||
mov1 = (pokemon.moves[0]) ? pokemon.moves[0].id : nil
|
|
||||||
mov2 = (pokemon.moves[1]) ? pokemon.moves[1].id : nil
|
|
||||||
mov3 = (pokemon.moves[2]) ? pokemon.moves[2].id : nil
|
|
||||||
mov4 = (pokemon.moves[3]) ? pokemon.moves[3].id : nil
|
|
||||||
ev_array = []
|
|
||||||
GameData::Stat.each_main do |s|
|
|
||||||
ev_array.push(s.id) if pokemon.ev[s.id] > 60
|
|
||||||
end
|
|
||||||
return self.new(pokemon.species,pokemon.item_id,pokemon.nature,
|
|
||||||
mov1,mov2,mov3,mov4,ev_array)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unused.
|
|
||||||
def self.constFromStr(mod,str)
|
|
||||||
maxconst=0
|
|
||||||
for constant in mod.constants
|
|
||||||
maxconst=[maxconst,mod.const_get(constant.to_sym)].max
|
|
||||||
end
|
|
||||||
for i in 1..maxconst
|
|
||||||
val=mod.getName(i)
|
|
||||||
next if nil_or_empty?(val)
|
|
||||||
return i if val==str
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unused.
|
|
||||||
def self.fromString(str)
|
|
||||||
return self.fromstring(str)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unused.
|
|
||||||
def self.fromstring(str)
|
|
||||||
s=str.split(/\s*,\s*/)
|
|
||||||
species=GameData::Species.get(s[1]).id
|
|
||||||
item=s[2].to_sym
|
|
||||||
nature=GameData::Nature.get(s[3]).id
|
|
||||||
move1=GameData::Move.get(s[4]).id
|
|
||||||
move2=(s.length>=12) ? GameData::Move.get(s[5]).id : nil
|
|
||||||
move3=(s.length>=13) ? GameData::Move.get(s[6]).id : nil
|
|
||||||
move4=(s.length>=14) ? GameData::Move.get(s[7]).id : nil
|
|
||||||
slen = s.length - 6
|
|
||||||
ev_array = []
|
|
||||||
GameData::Stat.each_main do |s|
|
|
||||||
ev_array.push(s.id) if s[slen + s.pbs_order].to_i > 0
|
|
||||||
end
|
|
||||||
return self.new(species,item,nature,move1,move2,move3,move4,ev_array)
|
|
||||||
end
|
|
||||||
|
|
||||||
=begin
|
|
||||||
def _dump(depth)
|
|
||||||
return [@species,@item,@nature,@move1,@move2,
|
|
||||||
@move3,@move4,@ev].pack("vvCvvvvC")
|
|
||||||
end
|
|
||||||
|
|
||||||
def self._load(str)
|
|
||||||
data=str.unpack("vvCvvvvC")
|
|
||||||
return self.new(
|
|
||||||
data[0],data[1],data[2],data[3],
|
|
||||||
data[4],data[5],data[6],data[7]
|
|
||||||
)
|
|
||||||
end
|
|
||||||
=end
|
|
||||||
|
|
||||||
def inspect
|
|
||||||
c1=GameData::Species.get(@species).id.to_s
|
|
||||||
c2=(@item) ? GameData::Item.get(@item).id.to_s : ""
|
|
||||||
c3=(@nature) ? GameData::Nature.get(@nature).id.to_s : ""
|
|
||||||
evlist = ""
|
|
||||||
@ev.each do |stat|
|
|
||||||
evlist += "," if evlist != ""
|
|
||||||
evlist += stat.real_name_brief
|
|
||||||
end
|
|
||||||
c4=(@move1) ? GameData::Move.get(@move1).id_to_s : ""
|
|
||||||
c5=(@move2) ? GameData::Move.get(@move2).id_to_s : ""
|
|
||||||
c6=(@move3) ? GameData::Move.get(@move3).id_to_s : ""
|
|
||||||
c7=(@move4) ? GameData::Move.get(@move4).id_to_s : ""
|
|
||||||
return "#{c1};#{c2};#{c3};#{evlist};#{c4},#{c5},#{c6},#{c7}"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Unused.
|
|
||||||
def tocompact
|
|
||||||
return "#{species},#{item},#{nature},#{move1},#{move2},#{move3},#{move4},#{ev}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def convertMove(move)
|
|
||||||
move = :FRUSTRATION if move == :RETURN && GameData::Move.exists?(:FRUSTRATION)
|
|
||||||
return move
|
|
||||||
end
|
|
||||||
|
|
||||||
def createPokemon(level,iv,trainer)
|
|
||||||
pokemon=Pokemon.new(@species,level,trainer,false)
|
|
||||||
pokemon.item = @item
|
|
||||||
pokemon.personalID = rand(2**16) | rand(2**16) << 16
|
|
||||||
pokemon.nature = nature
|
|
||||||
pokemon.happiness=0
|
|
||||||
pokemon.moves[0] = Pokemon::Move.new(self.convertMove(@move1))
|
|
||||||
pokemon.moves[1] = (@move2) ? Pokemon::Move.new(self.convertMove(@move2)) : nil
|
|
||||||
pokemon.moves[2] = (@move3) ? Pokemon::Move.new(self.convertMove(@move3)) : nil
|
|
||||||
pokemon.moves[3] = (@move4) ? Pokemon::Move.new(self.convertMove(@move4)) : nil
|
|
||||||
pokemon.moves.compact!
|
|
||||||
if ev.length > 0
|
|
||||||
ev.each { |stat| pokemon.ev[stat] = Pokemon::EV_LIMIT / ev.length }
|
|
||||||
end
|
|
||||||
GameData::Stat.each_main { |s| pokemon.iv[s.id] = iv }
|
|
||||||
pokemon.calc_stats
|
|
||||||
return pokemon
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def pbGetBTTrainers(challengeID)
|
|
||||||
trlists=(load_data("Data/trainer_lists.dat") rescue [])
|
|
||||||
for i in 0...trlists.length
|
|
||||||
tr=trlists[i]
|
|
||||||
if !tr[5] && tr[2].include?(challengeID)
|
|
||||||
return tr[0]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i in 0...trlists.length
|
|
||||||
tr=trlists[i]
|
|
||||||
if tr[5] # is default list
|
|
||||||
return tr[0]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return []
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbGetBTPokemon(challengeID)
|
|
||||||
trlists=(load_data("Data/trainer_lists.dat") rescue [])
|
|
||||||
for tr in trlists
|
|
||||||
if !tr[5] && tr[2].include?(challengeID)
|
|
||||||
return tr[1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for tr in trlists
|
|
||||||
if tr[5] # is default list
|
|
||||||
return tr[1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return []
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Game_Player < Game_Character
|
|
||||||
attr_accessor :direction
|
|
||||||
|
|
||||||
def moveto2(x, y)
|
|
||||||
@x = x
|
|
||||||
@y = y
|
|
||||||
@real_x = @x * 128
|
|
||||||
@real_y = @y * 128
|
|
||||||
@prelock_direction = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BattleChallengeType
|
|
||||||
attr_accessor :currentWins
|
|
||||||
attr_accessor :previousWins
|
|
||||||
attr_accessor :maxWins
|
|
||||||
attr_accessor :currentSwaps
|
|
||||||
attr_accessor :previousSwaps
|
|
||||||
attr_accessor :maxSwaps
|
|
||||||
attr_reader :doublebattle
|
|
||||||
attr_reader :numPokemon
|
|
||||||
attr_reader :battletype
|
|
||||||
attr_reader :mode
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@previousWins=0
|
|
||||||
@maxWins=0
|
|
||||||
@currentWins=0
|
|
||||||
@currentSwaps=0
|
|
||||||
@previousSwaps=0
|
|
||||||
@maxSwaps=0
|
|
||||||
end
|
|
||||||
|
|
||||||
def saveWins(challenge)
|
|
||||||
if challenge.decision==0 # if undecided
|
|
||||||
@currentWins=0
|
|
||||||
@currentSwaps=0
|
|
||||||
else
|
|
||||||
if challenge.decision==1 # if won
|
|
||||||
@currentWins=challenge.wins
|
|
||||||
@currentSwaps=challenge.swaps
|
|
||||||
else # if lost
|
|
||||||
@currentWins=0
|
|
||||||
@currentSwaps=0
|
|
||||||
end
|
|
||||||
@maxWins=[@maxWins,challenge.wins].max
|
|
||||||
@previousWins=challenge.wins
|
|
||||||
@maxSwaps=[@maxSwaps,challenge.swaps].max
|
|
||||||
@previousSwaps=challenge.swaps
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BattleChallengeData
|
|
||||||
attr_reader :resting
|
|
||||||
attr_reader :wins
|
|
||||||
attr_reader :swaps
|
|
||||||
attr_reader :inProgress
|
|
||||||
attr_reader :battleNumber
|
|
||||||
attr_reader :numRounds
|
|
||||||
attr_accessor :decision
|
|
||||||
attr_reader :party
|
|
||||||
attr_reader :extraData
|
|
||||||
|
|
||||||
def setExtraData(value)
|
|
||||||
@extraData=value
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbAddWin
|
|
||||||
if @inProgress
|
|
||||||
@battleNumber+=1
|
|
||||||
@wins+=1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbAddSwap
|
|
||||||
if @inProgress
|
|
||||||
@swaps+=1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbMatchOver?
|
|
||||||
return true if !@inProgress
|
|
||||||
return true if @decision!=0
|
|
||||||
return (@battleNumber>@numRounds)
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
reset
|
|
||||||
end
|
|
||||||
|
|
||||||
def nextTrainer
|
|
||||||
return @trainers[@battleNumber-1]
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbGoToStart
|
|
||||||
if $scene.is_a?(Scene_Map)
|
|
||||||
$game_temp.player_transferring = true
|
|
||||||
$game_temp.player_new_map_id = @start[0]
|
|
||||||
$game_temp.player_new_x = @start[1]
|
|
||||||
$game_temp.player_new_y = @start[2]
|
|
||||||
$game_temp.player_new_direction = 8
|
|
||||||
$scene.transfer_player
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def setParty(value)
|
|
||||||
if @inProgress
|
|
||||||
$Trainer.party=value
|
|
||||||
@party=value
|
|
||||||
else
|
|
||||||
@party=value
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbStart(t,numRounds)
|
|
||||||
@inProgress=true
|
|
||||||
@resting=false
|
|
||||||
@decision=0
|
|
||||||
@swaps=t.currentSwaps
|
|
||||||
@wins=t.currentWins
|
|
||||||
@battleNumber=1
|
|
||||||
@trainers=[]
|
|
||||||
raise _INTL("Number of rounds is 0 or less.") if numRounds<=0
|
|
||||||
@numRounds=numRounds
|
|
||||||
btTrainers=pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
|
||||||
while @trainers.length<@numRounds
|
|
||||||
newtrainer=pbBattleChallengeTrainer(@wins+@trainers.length,btTrainers)
|
|
||||||
found=false
|
|
||||||
for tr in @trainers
|
|
||||||
found=true if tr==newtrainer
|
|
||||||
end
|
|
||||||
@trainers.push(newtrainer) if !found
|
|
||||||
end
|
|
||||||
@start=[$game_map.map_id,$game_player.x,$game_player.y]
|
|
||||||
@oldParty=$Trainer.party
|
|
||||||
$Trainer.party=@party if @party
|
|
||||||
Game.save(safe: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbCancel
|
|
||||||
$Trainer.party=@oldParty if @oldParty
|
|
||||||
reset
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbEnd
|
|
||||||
$Trainer.party=@oldParty
|
|
||||||
return if !@inProgress
|
|
||||||
save=(@decision!=0)
|
|
||||||
reset
|
|
||||||
$game_map.need_refresh=true
|
|
||||||
Game.save(safe: true) if save
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbGoOn
|
|
||||||
return if !@inProgress
|
|
||||||
@resting=false
|
|
||||||
pbSaveInProgress
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbRest
|
|
||||||
return if !@inProgress
|
|
||||||
@resting=true
|
|
||||||
pbSaveInProgress
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def reset
|
|
||||||
@inProgress=false
|
|
||||||
@resting=false
|
|
||||||
@start=nil
|
|
||||||
@decision=0
|
|
||||||
@wins=0
|
|
||||||
@swaps=0
|
|
||||||
@battleNumber=0
|
|
||||||
@trainers=[]
|
|
||||||
@oldParty=nil
|
|
||||||
@party=nil
|
|
||||||
@extraData=nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbSaveInProgress
|
|
||||||
oldmapid=$game_map.map_id
|
|
||||||
oldx=$game_player.x
|
|
||||||
oldy=$game_player.y
|
|
||||||
olddirection=$game_player.direction
|
|
||||||
$game_map.map_id=@start[0]
|
|
||||||
$game_player.moveto2(@start[1],@start[2])
|
|
||||||
$game_player.direction=8 # facing up
|
|
||||||
Game.save(safe: true)
|
|
||||||
$game_map.map_id=oldmapid
|
|
||||||
$game_player.moveto2(oldx,oldy)
|
|
||||||
$game_player.direction=olddirection
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BattleChallenge
|
|
||||||
attr_reader :currentChallenge
|
|
||||||
BattleTowerID = 0
|
|
||||||
BattlePalaceID = 1
|
|
||||||
BattleArenaID = 2
|
|
||||||
BattleFactoryID = 3
|
|
||||||
|
|
||||||
def initialize
|
|
||||||
@bc=BattleChallengeData.new
|
|
||||||
@currentChallenge=-1
|
|
||||||
@types={}
|
|
||||||
end
|
|
||||||
|
|
||||||
def rules
|
|
||||||
if !@rules
|
|
||||||
@rules=modeToRules(self.data.doublebattle,
|
|
||||||
self.data.numPokemon,
|
|
||||||
self.data.battletype,self.data.mode)
|
|
||||||
end
|
|
||||||
return @rules
|
|
||||||
end
|
|
||||||
|
|
||||||
def modeToRules(doublebattle,numPokemon,battletype,mode)
|
|
||||||
rules=PokemonChallengeRules.new
|
|
||||||
if battletype==BattlePalaceID
|
|
||||||
rules.setBattleType(BattlePalace.new)
|
|
||||||
elsif battletype==BattleArenaID
|
|
||||||
rules.setBattleType(BattleArena.new)
|
|
||||||
doublebattle=false
|
|
||||||
else
|
|
||||||
rules.setBattleType(BattleTower.new)
|
|
||||||
end
|
|
||||||
if mode==1 # Open Level
|
|
||||||
rules.setRuleset(StandardRules(numPokemon,GameData::GrowthRate.max_level))
|
|
||||||
rules.setLevelAdjustment(OpenLevelAdjustment.new(30))
|
|
||||||
elsif mode==2 # Battle Tent
|
|
||||||
rules.setRuleset(StandardRules(numPokemon,GameData::GrowthRate.max_level))
|
|
||||||
rules.setLevelAdjustment(OpenLevelAdjustment.new(60))
|
|
||||||
else
|
|
||||||
rules.setRuleset(StandardRules(numPokemon,50))
|
|
||||||
rules.setLevelAdjustment(OpenLevelAdjustment.new(50))
|
|
||||||
end
|
|
||||||
if doublebattle
|
|
||||||
rules.addBattleRule(DoubleBattle.new)
|
|
||||||
else
|
|
||||||
rules.addBattleRule(SingleBattle.new)
|
|
||||||
end
|
|
||||||
return rules
|
|
||||||
end
|
|
||||||
|
|
||||||
def set(id,numrounds,rules)
|
|
||||||
@id=id
|
|
||||||
@numRounds=numrounds
|
|
||||||
@rules=rules
|
|
||||||
pbWriteCup(id,rules)
|
|
||||||
end
|
|
||||||
|
|
||||||
def start(*args)
|
|
||||||
t = ensureType(@id)
|
|
||||||
@currentChallenge=@id # must appear before pbStart
|
|
||||||
@bc.pbStart(t,@numRounds)
|
|
||||||
end
|
|
||||||
|
|
||||||
def register(id,doublebattle,numrounds,numPokemon,battletype,mode=1)
|
|
||||||
ensureType(id)
|
|
||||||
if battletype==BattleFactoryID
|
|
||||||
@bc.setExtraData(BattleFactoryData.new(@bc))
|
|
||||||
numPokemon=3
|
|
||||||
battletype=BattleTowerID
|
|
||||||
end
|
|
||||||
@numRounds=numrounds
|
|
||||||
@rules=modeToRules(doublebattle,numPokemon,battletype,mode)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbInChallenge?
|
|
||||||
return pbInProgress?
|
|
||||||
end
|
|
||||||
|
|
||||||
def data
|
|
||||||
return nil if !pbInProgress? || @currentChallenge<0
|
|
||||||
return ensureType(@currentChallenge).clone
|
|
||||||
end
|
|
||||||
|
|
||||||
def getCurrentWins(challenge)
|
|
||||||
return ensureType(challenge).currentWins
|
|
||||||
end
|
|
||||||
|
|
||||||
def getPreviousWins(challenge)
|
|
||||||
return ensureType(challenge).previousWins
|
|
||||||
end
|
|
||||||
|
|
||||||
def getMaxWins(challenge)
|
|
||||||
return ensureType(challenge).maxWins
|
|
||||||
end
|
|
||||||
|
|
||||||
def getCurrentSwaps(challenge)
|
|
||||||
return ensureType(challenge).currentSwaps
|
|
||||||
end
|
|
||||||
|
|
||||||
def getPreviousSwaps(challenge)
|
|
||||||
return ensureType(challenge).previousSwaps
|
|
||||||
end
|
|
||||||
|
|
||||||
def getMaxSwaps(challenge)
|
|
||||||
return ensureType(challenge).maxSwaps
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbStart(challenge)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbEnd
|
|
||||||
if @currentChallenge!=-1
|
|
||||||
ensureType(@currentChallenge).saveWins(@bc)
|
|
||||||
@currentChallenge=-1
|
|
||||||
end
|
|
||||||
@bc.pbEnd
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbBattle
|
|
||||||
return @bc.extraData.pbBattle(self) if @bc.extraData
|
|
||||||
opponent=pbGenerateBattleTrainer(self.nextTrainer,self.rules)
|
|
||||||
bttrainers=pbGetBTTrainers(@id)
|
|
||||||
trainerdata=bttrainers[self.nextTrainer]
|
|
||||||
ret=pbOrganizedBattleEx(opponent,self.rules,
|
|
||||||
pbGetMessageFromHash(MessageTypes::EndSpeechLose,trainerdata[4]),
|
|
||||||
pbGetMessageFromHash(MessageTypes::EndSpeechWin,trainerdata[3]))
|
|
||||||
return ret
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbInProgress?
|
|
||||||
return @bc.inProgress
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbResting?
|
|
||||||
return @bc.resting
|
|
||||||
end
|
|
||||||
|
|
||||||
def setDecision(value)
|
|
||||||
@bc.decision=value
|
|
||||||
end
|
|
||||||
|
|
||||||
def setParty(value)
|
|
||||||
@bc.setParty(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def extra; @bc.extraData; end
|
|
||||||
def decision; @bc.decision; end
|
|
||||||
def wins; @bc.wins; end
|
|
||||||
def swaps; @bc.swaps; end
|
|
||||||
def battleNumber; @bc.battleNumber; end
|
|
||||||
def nextTrainer; @bc.nextTrainer; end
|
|
||||||
def pbGoOn; @bc.pbGoOn; end
|
|
||||||
def pbAddWin; @bc.pbAddWin; end
|
|
||||||
def pbCancel; @bc.pbCancel; end
|
|
||||||
def pbRest; @bc.pbRest; end
|
|
||||||
def pbMatchOver?; @bc.pbMatchOver?; end
|
|
||||||
def pbGoToStart; @bc.pbGoToStart; end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def ensureType(id)
|
|
||||||
if @types.is_a?(Array)
|
|
||||||
oldtypes=@types
|
|
||||||
@types={}
|
|
||||||
for i in 0...oldtypes.length
|
|
||||||
@types[i]=oldtypes[i] if oldtypes[i]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@types[id]=BattleChallengeType.new if !@types[id]
|
|
||||||
return @types[id]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def pbRecordLastBattle
|
|
||||||
$PokemonGlobal.lastbattle = $PokemonTemp.lastbattle
|
|
||||||
$PokemonTemp.lastbattle = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbPlayBattle(battledata)
|
|
||||||
return if !battledata
|
|
||||||
scene = pbNewBattleScene
|
|
||||||
scene.abortable = true
|
|
||||||
lastbattle = Marshal.restore(StringInput.new(battledata))
|
|
||||||
case lastbattle[0]
|
|
||||||
when BattleChallenge::BattleTowerID
|
|
||||||
battleplayer = PokeBattle_BattlePlayer.new(scene,lastbattle)
|
|
||||||
when BattleChallenge::BattlePalaceID
|
|
||||||
battleplayer = PokeBattle_BattlePalacePlayer.new(scene,lastbattle)
|
|
||||||
when BattleChallenge::BattleArenaID
|
|
||||||
battleplayer = PokeBattle_BattleArenaPlayer.new(scene,lastbattle)
|
|
||||||
end
|
|
||||||
bgm = BattlePlayerHelper.pbGetBattleBGM(lastbattle)
|
|
||||||
pbBattleAnimation(bgm) {
|
|
||||||
pbSceneStandby {
|
|
||||||
battleplayer.pbStartBattle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbDebugPlayBattle
|
|
||||||
params = ChooseNumberParams.new
|
|
||||||
params.setRange(0,500)
|
|
||||||
params.setInitialValue(0)
|
|
||||||
params.setCancelValue(-1)
|
|
||||||
num = pbMessageChooseNumber(_INTL("Choose a battle."),params)
|
|
||||||
if num>=0
|
|
||||||
pbPlayBattleFromFile(sprintf("Battles/Battle%03d.dat",num))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbPlayLastBattle
|
|
||||||
pbPlayBattle($PokemonGlobal.lastbattle)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbPlayBattleFromFile(filename)
|
|
||||||
pbRgssOpen(filename,"rb") { |f| pbPlayBattle(f.read) }
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Game_Event
|
|
||||||
def pbInChallenge?
|
|
||||||
return pbBattleChallenge.pbInChallenge?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def pbBattleChallenge
|
|
||||||
if !$PokemonGlobal.challenge
|
|
||||||
$PokemonGlobal.challenge=BattleChallenge.new
|
|
||||||
end
|
|
||||||
return $PokemonGlobal.challenge
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbBattleChallengeTrainer(numwins,bttrainers)
|
|
||||||
table=[
|
|
||||||
0,5,0,100,
|
|
||||||
6,6,80,40,
|
|
||||||
7,12,80,40,
|
|
||||||
13,13,120,20,
|
|
||||||
14,19,100,40,
|
|
||||||
20,20,140,20,
|
|
||||||
21,26,120,40,
|
|
||||||
27,27,160,20,
|
|
||||||
28,33,140,40,
|
|
||||||
34,34,180,20,
|
|
||||||
35,40,160,40,
|
|
||||||
41,41,200,20,
|
|
||||||
42,47,180,40,
|
|
||||||
48,48,220,40,
|
|
||||||
49,-1,200,100
|
|
||||||
]
|
|
||||||
for i in 0...table.length/4
|
|
||||||
if table[i*4]<=numwins
|
|
||||||
if (table[i*4+1]<0 || table[i*4+1]>=numwins)
|
|
||||||
offset=((table[i*4+2]*bttrainers.length).floor/300).floor
|
|
||||||
length=((table[i*4+3]*bttrainers.length).floor/300).floor
|
|
||||||
return (offset+rand(length)).floor
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbBattleChallengeGraphic(event)
|
|
||||||
nextTrainer=pbBattleChallenge.nextTrainer
|
|
||||||
bttrainers=pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
|
||||||
filename=GameData::TrainerType.charset_filename_brief((bttrainers[nextTrainer][0] rescue nil))
|
|
||||||
begin
|
|
||||||
filename = "NPC 01" if nil_or_empty?(filename)
|
|
||||||
bitmap=AnimatedBitmap.new("Graphics/Characters/"+filename)
|
|
||||||
bitmap.dispose
|
|
||||||
event.character_name=filename
|
|
||||||
rescue
|
|
||||||
event.character_name="NPC 01"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbBattleChallengeBeginSpeech
|
|
||||||
if !pbBattleChallenge.pbInProgress?
|
|
||||||
return "..."
|
|
||||||
else
|
|
||||||
bttrainers=pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
|
||||||
tr=bttrainers[pbBattleChallenge.nextTrainer]
|
|
||||||
return tr ? pbGetMessageFromHash(MessageTypes::BeginSpeech,tr[2]) : "..."
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbEntryScreen(*arg)
|
|
||||||
retval = false
|
|
||||||
pbFadeOutIn {
|
|
||||||
scene = PokemonParty_Scene.new
|
|
||||||
screen = PokemonPartyScreen.new(scene,$Trainer.party)
|
|
||||||
ret = screen.pbPokemonMultipleEntryScreenEx(pbBattleChallenge.rules.ruleset)
|
|
||||||
# Set party
|
|
||||||
pbBattleChallenge.setParty(ret) if ret
|
|
||||||
# Continue (return true) if Pokémon were chosen
|
|
||||||
retval = (ret!=nil && ret.length>0)
|
|
||||||
}
|
|
||||||
return retval
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbBattleChallengeBattle
|
|
||||||
return pbBattleChallenge.pbBattle
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class BattleFactoryData
|
|
||||||
def initialize(bcdata)
|
|
||||||
@bcdata=bcdata
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbPrepareRentals
|
|
||||||
@rentals=pbBattleFactoryPokemon(1,@bcdata.wins,@bcdata.swaps,[])
|
|
||||||
@trainerid=@bcdata.nextTrainer
|
|
||||||
bttrainers=pbGetBTTrainers(@bcdata.currentChallenge)
|
|
||||||
trainerdata=bttrainers[@trainerid]
|
|
||||||
@opponent=NPCTrainer.new(
|
|
||||||
pbGetMessageFromHash(MessageTypes::TrainerNames,trainerdata[1]),
|
|
||||||
trainerdata[0])
|
|
||||||
opponentPkmn=pbBattleFactoryPokemon(1,@bcdata.wins,@bcdata.swaps,@rentals)
|
|
||||||
@opponent.party=opponentPkmn.shuffle[0,3]
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbChooseRentals
|
|
||||||
pbFadeOutIn {
|
|
||||||
scene = BattleSwapScene.new
|
|
||||||
screen = BattleSwapScreen.new(scene)
|
|
||||||
@rentals = screen.pbStartRent(@rentals)
|
|
||||||
@bcdata.pbAddSwap
|
|
||||||
pbBattleChallenge.setParty(@rentals)
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbBattle(challenge)
|
|
||||||
bttrainers=pbGetBTTrainers(@bcdata.currentChallenge)
|
|
||||||
trainerdata=bttrainers[@trainerid]
|
|
||||||
return pbOrganizedBattleEx(@opponent,challenge.rules,
|
|
||||||
pbGetMessageFromHash(MessageTypes::EndSpeechLose,trainerdata[4]),
|
|
||||||
pbGetMessageFromHash(MessageTypes::EndSpeechWin,trainerdata[3]))
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbPrepareSwaps
|
|
||||||
@oldopponent=@opponent.party
|
|
||||||
trainerid=@bcdata.nextTrainer
|
|
||||||
bttrainers=pbGetBTTrainers(@bcdata.currentChallenge)
|
|
||||||
trainerdata=bttrainers[trainerid]
|
|
||||||
@opponent=NPCTrainer.new(
|
|
||||||
pbGetMessageFromHash(MessageTypes::TrainerNames,trainerdata[1]),
|
|
||||||
trainerdata[0])
|
|
||||||
opponentPkmn=pbBattleFactoryPokemon(
|
|
||||||
challenge.rules,@bcdata.wins,@bcdata.swaps,
|
|
||||||
[].concat(@rentals).concat(@oldopponent))
|
|
||||||
@opponent.party=opponentPkmn.shuffle[0,3]
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbChooseSwaps
|
|
||||||
swapMade = true
|
|
||||||
pbFadeOutIn {
|
|
||||||
scene = BattleSwapScene.new
|
|
||||||
screen = BattleSwapScreen.new(scene)
|
|
||||||
swapMade = screen.pbStartSwap(@rentals,@oldopponent)
|
|
||||||
if swapMade
|
|
||||||
@bcdata.pbAddSwap
|
|
||||||
end
|
|
||||||
@bcdata.setParty(@rentals)
|
|
||||||
}
|
|
||||||
return swapMade
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def pbBattleFactoryPokemon(rule,numwins,numswaps,_rentals)
|
|
||||||
table=nil
|
|
||||||
btpokemon=pbGetBTPokemon(pbBattleChallenge.currentChallenge)
|
|
||||||
ivtable=[
|
|
||||||
0,6,3,6,
|
|
||||||
7,13,6,9,
|
|
||||||
14,20,9,12,
|
|
||||||
21,27,12,15,
|
|
||||||
28,34,15,21,
|
|
||||||
35,41,21,31,
|
|
||||||
42,-1,31,31
|
|
||||||
]
|
|
||||||
groups=[
|
|
||||||
1,14,6,0,
|
|
||||||
15,21,5,1,
|
|
||||||
22,28,4,2,
|
|
||||||
29,35,3,3,
|
|
||||||
36,42,2,4,
|
|
||||||
43,-1,1,5
|
|
||||||
]
|
|
||||||
if rule.ruleset.suggestedLevel!=100
|
|
||||||
table=[
|
|
||||||
0,6,110,199,
|
|
||||||
7,13,162,266,
|
|
||||||
14,20,267,371,
|
|
||||||
21,27,372,467,
|
|
||||||
28,34,468,563,
|
|
||||||
35,41,564,659,
|
|
||||||
42,48,660,755,
|
|
||||||
49,-1,372,849
|
|
||||||
]
|
|
||||||
else # Open Level (Level 100)
|
|
||||||
table=[
|
|
||||||
0,6,372,467,
|
|
||||||
7,13,468,563,
|
|
||||||
14,20,564,659,
|
|
||||||
21,27,660,755,
|
|
||||||
28,34,372,881,
|
|
||||||
35,41,372,881,
|
|
||||||
42,48,372,881,
|
|
||||||
49,-1,372,881
|
|
||||||
]
|
|
||||||
end
|
|
||||||
pokemonNumbers=[0,0]
|
|
||||||
ivs=[0,0]
|
|
||||||
ivgroups=[6,0]
|
|
||||||
for i in 0...table.length/4
|
|
||||||
if table[i*4]<=numwins
|
|
||||||
if (table[i*4+1]<0 || table[i*4+1]>=numwins)
|
|
||||||
pokemonNumbers=[
|
|
||||||
table[i*4+2]*btpokemon.length/882,
|
|
||||||
table[i*4+3]*btpokemon.length/882
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i in 0...ivtable.length/4
|
|
||||||
if ivtable[i*4]<=numwins
|
|
||||||
if (ivtable[i*4+1]<0 || ivtable[i*4+1]>=numwins)
|
|
||||||
ivs=[ivtable[i*4+2],ivtable[i*4+3]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i in 0...groups.length/4
|
|
||||||
if groups[i*4]<=numswaps
|
|
||||||
if (groups[i*4+1]<0 || groups[i*4+1]>=numswaps)
|
|
||||||
ivgroups=[groups[i*4+2],groups[i*4+3]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
party=[]
|
|
||||||
loop do
|
|
||||||
party.clear
|
|
||||||
while party.length < Settings::MAX_PARTY_SIZE
|
|
||||||
rnd=pokemonNumbers[0]+rand(pokemonNumbers[1]-pokemonNumbers[0]+1)
|
|
||||||
rndpoke=btpokemon[rnd]
|
|
||||||
indvalue=(party.length<ivgroups[0]) ? ivs[0] : ivs[1]
|
|
||||||
party.push(rndpoke.createPokemon(rule.ruleset.suggestedLevel,indvalue,nil))
|
|
||||||
end
|
|
||||||
break if rule.ruleset.isValid?(party)
|
|
||||||
end
|
|
||||||
return party
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbGenerateBattleTrainer(trainerid,rule)
|
|
||||||
bttrainers=pbGetBTTrainers(pbBattleChallenge.currentChallenge)
|
|
||||||
trainerdata=bttrainers[trainerid]
|
|
||||||
opponent=NPCTrainer.new(
|
|
||||||
pbGetMessageFromHash(MessageTypes::TrainerNames,trainerdata[1]),
|
|
||||||
trainerdata[0])
|
|
||||||
btpokemon=pbGetBTPokemon(pbBattleChallenge.currentChallenge)
|
|
||||||
# Individual Values
|
|
||||||
indvalues=31
|
|
||||||
indvalues=21 if trainerid<220
|
|
||||||
indvalues=18 if trainerid<200
|
|
||||||
indvalues=15 if trainerid<180
|
|
||||||
indvalues=12 if trainerid<160
|
|
||||||
indvalues=9 if trainerid<140
|
|
||||||
indvalues=6 if trainerid<120
|
|
||||||
indvalues=3 if trainerid<100
|
|
||||||
pokemonnumbers=trainerdata[5]
|
|
||||||
#p trainerdata
|
|
||||||
if pokemonnumbers.length<rule.ruleset.suggestedNumber
|
|
||||||
for n in pokemonnumbers
|
|
||||||
rndpoke=btpokemon[n]
|
|
||||||
pkmn=rndpoke.createPokemon(rule.ruleset.suggestedLevel,indvalues,opponent)
|
|
||||||
opponent.party.push(pkmn)
|
|
||||||
end
|
|
||||||
return opponent
|
|
||||||
end
|
|
||||||
loop do
|
|
||||||
opponent.party.clear
|
|
||||||
while opponent.party.length<rule.ruleset.suggestedNumber
|
|
||||||
rnd=pokemonnumbers[rand(pokemonnumbers.length)]
|
|
||||||
rndpoke=btpokemon[rnd]
|
|
||||||
pkmn=rndpoke.createPokemon(
|
|
||||||
rule.ruleset.suggestedLevel,indvalues,opponent)
|
|
||||||
opponent.party.push(pkmn)
|
|
||||||
end
|
|
||||||
break if rule.ruleset.isValid?(opponent.party)
|
|
||||||
end
|
|
||||||
return opponent
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbOrganizedBattleEx(opponent,challengedata,endspeech,endspeechwin)
|
|
||||||
# Skip battle if holding Ctrl in Debug mode
|
|
||||||
if Input.press?(Input::CTRL) && $DEBUG
|
|
||||||
pbMessage(_INTL("SKIPPING BATTLE..."))
|
|
||||||
pbMessage(_INTL("AFTER WINNING..."))
|
|
||||||
endspeech.each { |msg| pbMessage(msg || "...") }
|
|
||||||
$PokemonTemp.lastbattle = nil
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
$Trainer.heal_party
|
|
||||||
# Remember original data, to be restored after battle
|
|
||||||
challengedata = PokemonChallengeRules.new if !challengedata
|
|
||||||
oldlevels = challengedata.adjustLevels($Trainer.party,opponent.party)
|
|
||||||
olditems = $Trainer.party.transform { |p| p.item_id }
|
|
||||||
olditems2 = opponent.party.transform { |p| p.item_id }
|
|
||||||
# Create the battle scene (the visual side of it)
|
|
||||||
scene = pbNewBattleScene
|
|
||||||
# Create the battle class (the mechanics side of it)
|
|
||||||
battle = challengedata.createBattle(scene,$Trainer,opponent)
|
|
||||||
battle.internalBattle = false
|
|
||||||
battle.endSpeeches = [endspeech]
|
|
||||||
battle.endSpeechesWin = [endspeechwin]
|
|
||||||
# Set various other properties in the battle class
|
|
||||||
pbPrepareBattle(battle)
|
|
||||||
# Perform the battle itself
|
|
||||||
decision = 0
|
|
||||||
pbBattleAnimation(pbGetTrainerBattleBGM(opponent)) {
|
|
||||||
pbSceneStandby{
|
|
||||||
decision = battle.pbStartBattle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Input.update
|
|
||||||
# Restore both parties to their original levels
|
|
||||||
challengedata.unadjustLevels($Trainer.party,opponent.party,oldlevels)
|
|
||||||
# Heal both parties and restore their original items
|
|
||||||
$Trainer.party.each_with_index do |pkmn,i|
|
|
||||||
pkmn.heal
|
|
||||||
pkmn.makeUnmega
|
|
||||||
pkmn.makeUnprimal
|
|
||||||
pkmn.item = olditems[i]
|
|
||||||
end
|
|
||||||
opponent.party.each_with_index do |pkmn,i|
|
|
||||||
pkmn.heal
|
|
||||||
pkmn.makeUnmega
|
|
||||||
pkmn.makeUnprimal
|
|
||||||
pkmn.item = olditems2[i]
|
|
||||||
end
|
|
||||||
# Save the record of the battle
|
|
||||||
$PokemonTemp.lastbattle = nil
|
|
||||||
if decision==1 || decision==2 || decision==5 # if win, loss or draw
|
|
||||||
$PokemonTemp.lastbattle = battle.pbDumpRecord
|
|
||||||
end
|
|
||||||
# Return true if the player won the battle, and false if any other result
|
|
||||||
return (decision==1)
|
|
||||||
end
|
|
||||||
|
|
||||||
def pbIsBanned?(pokemon)
|
|
||||||
return StandardSpeciesRestriction.new.isValid?(pokemon)
|
|
||||||
end
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user