Resource icon

Resource NPC Battles (NPC vs. NPC) 1.01

Hollow_Ego

Cooltrainer
Member
Joined
May 19, 2018
Posts
116
Hollow_Ego submitted a new resource:

NPC Battles (NPC vs. NPC) - Set up battles between 2 NPCs that th player can watch

NPC BATTLE SCRIPT

This script allows you to let two NPCs battle each other in an actual battle enviroment, so that the player can watch it. The outcome can not be modified.

Features:
- let any two NPCs battle that are defined in the trainer pbs
- allows double battles
- player can control the NPCs action if wanted
- doesn't level NPCs Pokemon
- doesn't effect players money
- by default each battle can be lost, so the player won't black out
- the party that is...

Read more about this resource...
 

ArchyArc

Lead Developer of Pokemon Sacred Johto
Member
Joined
May 10, 2017
Posts
38
Super interesting script, something i thought would be cool ages ago, glad to see someone technical did it!

works mostly okay, in a single 1v1 battle however i get like the trainers VS animation with the BW protagonists with the weird long message (can provide a screenshot) but not in double battles (might be the existing trainer classes)

and also crashes after ending. (calls to pbafterbattle, changed to to pbendbattle as of v16 but still the same thing)

any reason this might be? sorry to post here about it might just be a me thing

Edit: managed to fix it; changing it to "Events.onEndBattle.trigger(nil,decision,canlose)" seemed to work for me, since others havent complained im sure it works fine in 17 just was a backstep/downgrade thing
 
Last edited:

Hollow_Ego

Cooltrainer
Member
Joined
May 19, 2018
Posts
116
Super interesting script, something i thought would be cool ages ago, glad to see someone technical did it!

works mostly okay, in a single 1v1 battle however i get like the trainers VS animation with the BW protagonists with the weird long message (can provide a screenshot) but not in double battles (might be the existing trainer classes)

and also crashes after ending. (calls to pbafterbattle, changed to to pbendbattle as of v16 but still the same thing)

any reason this might be? sorry to post here about it might just be a me thing

Edit: managed to fix it; changing it to "Events.onEndBattle.trigger(nil,decision,canlose)" seemed to work for me, since others havent complained im sure it works fine in 17 just was a backstep/downgrade thing


Thank you for your feedback!

I'm glad you were able to fix the issue and appreciate that you posted the solutio.
 

ArchyArc

Lead Developer of Pokemon Sacred Johto
Member
Joined
May 10, 2017
Posts
38
So small issue, again might be a downgrade thing, when the npc on the players side loses there is no end speech (understandable) and the match ends almost abruptly and the pokemon icon bars remain (could be a thing to ebs too however) could easily fix this by swapping them around but felt i'd point it out.
 

ArchyArc

Lead Developer of Pokemon Sacred Johto
Member
Joined
May 10, 2017
Posts
38
so most likely a v17 script to v16 thing (even though the only removal was that of the afterbattle thing)

it pretty much breaks saves, moreso, before its fine, watch the battle then player pokemon items are broken (they are set to nil not 0 or the item (even if they have or havent got items) felt it was another issue but i used a version from like 2 months ago and i still get it. (not sure where to point to as the errors are that the .item of the players pokemon are 0.

might find a way to save the players party to a variable then give it back? might fix it. if you have any idea let me know but it seems tied to this script or moreso the battles (tested with trainers ones and it doesnt happen, so maybe since i downgraded it it somehow doesnt return the value for the player pokemon's items)
 

Hollow_Ego

Cooltrainer
Member
Joined
May 19, 2018
Posts
116
Hollow_Ego updated NPC Battles (NPC vs. NPC) with a new update entry:

Quick Update for v19 compatible version [manual installation]

Here is a quick update to this script, that is compatible with v19 of Essentials.
This does not make use of the plugin in system, so you will need to copy the contents of each file into a new script section.

Why release this?
I'm already working on a complete version vor Essentials, however it will take much more time, due to all the changes. However the simulated battles where easy to do and therefore I don't want to hold them back.

Find the files...

Read the rest of this update entry...
 

Hollow_Ego

Cooltrainer
Member
Joined
May 19, 2018
Posts
116
Please update to v19.1, I really love this amazing script :(((
I'm already working on a v19 version. However I'm stuck on the scripted battles part.
I made a quick update, so you can use the simulated part at least.
 

Neppii

Rookie
Member
Joined
Mar 11, 2022
Posts
3
EDIT: Okay I found the problem and this is the solution:
In 02_Shared_battle_Class change the the first line to
Ruby:
class PokeBattle_Simulated_Battle < PokeBattle_Battle
Also you need to make sure that the shared script sections come before the simulated ones.

Also you need to add the following function into an own script section above 04_Simulated_... script section:
Ruby:
#===============================================================================
# Make an enemy trainer slide off-screen from the right. Makes the previous
# trainer slide off to the right first if it is on-screen.
# Used at the end of battle.
#===============================================================================
class TrainerMessageDisappearAnimation < PokeBattle_Animation
  def initialize(sprites,viewport,idxTrainer,spriteNameBase)
    @idxTrainer = idxTrainer
    @spriteNameBase = spriteNameBase
    super(sprites,viewport)
  end

 
  def createProcesses
    delay = 0
    if @spriteNameBase=="trainer_"
      # Make trainer sprite move off-screen
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        newTrainer.moveDelta(delay,8,Graphics.width/4,0)
        newTrainer.setVisible(delay+8,false)
      end
    else
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        newTrainer.moveDelta(delay,8,-Graphics.width/4-64,0)
        newTrainer.setVisible(delay+8,false)
      end
    end
  end
end


#===============================================================================
# Make an enemy trainer slide on-screen from the right. Makes the previous
# trainer slide off to the right first if it is on-screen.
# Used at the end of battle.
#===============================================================================
class TrainerMessageAppearAnimation < PokeBattle_Animation
  def initialize(sprites,viewport,idxTrainer,spriteNameBase)
    @idxTrainer = idxTrainer
    @spriteNameBase = spriteNameBase
    super(sprites,viewport)
  end

  def createProcesses
    delay = 0
    offset = 64
    if @spriteNameBase=="trainer_"
      # Make old trainer sprite move off-screen first if necessary
      if @idxTrainer>0 && @sprites["#{@spriteNameBase}#{@idxTrainer}"].visible
        oldTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer}"],PictureOrigin::Bottom)
        oldTrainer.moveDelta(delay,8,Graphics.width/4,0)
        oldTrainer.setVisible(delay+8,false)
        delay = oldTrainer.totalDuration
      end
      # Make new trainer sprite move on-screen
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        trainerX, trainerY = PokeBattle_SceneConstants.pbTrainerPosition(1)
        trainerX += 64+Graphics.width/4
        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        newTrainer.setVisible(delay,true)
        newTrainer.setXY(delay,trainerX,trainerY)
        newTrainer.moveDelta(delay,8,-Graphics.width/4,0)
      end
    else
      # Make old trainer sprite move off-screen first if necessary
      if @idxTrainer>0 && @sprites["#{@spriteNameBase}#{@idxTrainer}"].visible
        oldTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer}"],PictureOrigin::Bottom)
        oldTrainer.moveDelta(delay,8,-Graphics.width/4-offset,0)
        oldTrainer.setVisible(delay+8,false)
        delay = oldTrainer.totalDuration
      end
      # Make new trainer sprite move on-screen
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        trainerX, trainerY = PokeBattle_SceneConstants.pbTrainerPosition(1)

        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        size = newTrainer.src_rect.width   # Width per frame
        if newTrainer.x!= -96
          newTrainer.x = -96
        end
        newTrainer.setSrc(0,size,0)
        newTrainer.setZ(0,100)
        newTrainer.setVisible(delay,true)
        newTrainer.moveDelta(delay,8,Graphics.width/4+offset,0)
      end
    end
  end
end

class PokeBattle_Scene
 
  #=============================================================================
  # Animates an opposing trainer sliding off from off-screen.
  #=============================================================================
  def pbHideTrainerForMessage(idxTrainer,spriteNameBase)
    # Set up trainer appearing animation
    disappearAnim = TrainerMessageDisappearAnimation.new(@sprites,@viewport,idxTrainer,spriteNameBase)
    @animations.push(disappearAnim)
    # Play the animation
    while inPartyAnimation?; pbUpdate; end
    end
   
   
    #=============================================================================
  # Animates an opposing trainer sliding in from off-screen. Will animate a
  # previous trainer that is already on-screen slide off first. Used at the end
  # of battle.
  #=============================================================================
  def pbShowTrainerForMessage(idxTrainer,spriteNameBase)
    # Set up trainer appearing animation
    appearAnim = TrainerMessageAppearAnimation.new(@sprites,@viewport,idxTrainer,spriteNameBase)
    @animations.push(appearAnim)
    # Play the animation
    while inPartyAnimation?; pbUpdate; end
  end
end

After all these changes it works like a charm. The script to start the battle is for example
pbSimulatedTrainerBattle(pbLoadTrainer(:TRAINER_A,"Aron"),pbLoadTrainer(:TRAINER_B,"Bob"))
 
Last edited:

Hollow_Ego

Cooltrainer
Member
Joined
May 19, 2018
Posts
116
EDIT: Okay I found the problem and this is the solution:
In 02_Shared_battle_Class change the the first line to
Ruby:
class PokeBattle_Simulated_Battle < PokeBattle_Battle
Also you need to make sure that the shared script sections come before the simulated ones.

Also you need to add the following function into an own script section above 04_Simulated_... script section:
Ruby:
#===============================================================================
# Make an enemy trainer slide off-screen from the right. Makes the previous
# trainer slide off to the right first if it is on-screen.
# Used at the end of battle.
#===============================================================================
class TrainerMessageDisappearAnimation < PokeBattle_Animation
  def initialize(sprites,viewport,idxTrainer,spriteNameBase)
    @idxTrainer = idxTrainer
    @spriteNameBase = spriteNameBase
    super(sprites,viewport)
  end

 
  def createProcesses
    delay = 0
    if @spriteNameBase=="trainer_"
      # Make trainer sprite move off-screen
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        newTrainer.moveDelta(delay,8,Graphics.width/4,0)
        newTrainer.setVisible(delay+8,false)
      end
    else
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        newTrainer.moveDelta(delay,8,-Graphics.width/4-64,0)
        newTrainer.setVisible(delay+8,false)
      end
    end
  end
end


#===============================================================================
# Make an enemy trainer slide on-screen from the right. Makes the previous
# trainer slide off to the right first if it is on-screen.
# Used at the end of battle.
#===============================================================================
class TrainerMessageAppearAnimation < PokeBattle_Animation
  def initialize(sprites,viewport,idxTrainer,spriteNameBase)
    @idxTrainer = idxTrainer
    @spriteNameBase = spriteNameBase
    super(sprites,viewport)
  end

  def createProcesses
    delay = 0
    offset = 64
    if @spriteNameBase=="trainer_"
      # Make old trainer sprite move off-screen first if necessary
      if @idxTrainer>0 && @sprites["#{@spriteNameBase}#{@idxTrainer}"].visible
        oldTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer}"],PictureOrigin::Bottom)
        oldTrainer.moveDelta(delay,8,Graphics.width/4,0)
        oldTrainer.setVisible(delay+8,false)
        delay = oldTrainer.totalDuration
      end
      # Make new trainer sprite move on-screen
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        trainerX, trainerY = PokeBattle_SceneConstants.pbTrainerPosition(1)
        trainerX += 64+Graphics.width/4
        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        newTrainer.setVisible(delay,true)
        newTrainer.setXY(delay,trainerX,trainerY)
        newTrainer.moveDelta(delay,8,-Graphics.width/4,0)
      end
    else
      # Make old trainer sprite move off-screen first if necessary
      if @idxTrainer>0 && @sprites["#{@spriteNameBase}#{@idxTrainer}"].visible
        oldTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer}"],PictureOrigin::Bottom)
        oldTrainer.moveDelta(delay,8,-Graphics.width/4-offset,0)
        oldTrainer.setVisible(delay+8,false)
        delay = oldTrainer.totalDuration
      end
      # Make new trainer sprite move on-screen
      if @sprites["#{@spriteNameBase}#{@idxTrainer+1}"]
        trainerX, trainerY = PokeBattle_SceneConstants.pbTrainerPosition(1)

        newTrainer = addSprite(@sprites["#{@spriteNameBase}#{@idxTrainer+1}"],PictureOrigin::Bottom)
        size = newTrainer.src_rect.width   # Width per frame
        if newTrainer.x!= -96
          newTrainer.x = -96
        end
        newTrainer.setSrc(0,size,0)
        newTrainer.setZ(0,100)
        newTrainer.setVisible(delay,true)
        newTrainer.moveDelta(delay,8,Graphics.width/4+offset,0)
      end
    end
  end
end

class PokeBattle_Scene
 
  #=============================================================================
  # Animates an opposing trainer sliding off from off-screen.
  #=============================================================================
  def pbHideTrainerForMessage(idxTrainer,spriteNameBase)
    # Set up trainer appearing animation
    disappearAnim = TrainerMessageDisappearAnimation.new(@sprites,@viewport,idxTrainer,spriteNameBase)
    @animations.push(disappearAnim)
    # Play the animation
    while inPartyAnimation?; pbUpdate; end
    end
  
  
    #=============================================================================
  # Animates an opposing trainer sliding in from off-screen. Will animate a
  # previous trainer that is already on-screen slide off first. Used at the end
  # of battle.
  #=============================================================================
  def pbShowTrainerForMessage(idxTrainer,spriteNameBase)
    # Set up trainer appearing animation
    appearAnim = TrainerMessageAppearAnimation.new(@sprites,@viewport,idxTrainer,spriteNameBase)
    @animations.push(appearAnim)
    # Play the animation
    while inPartyAnimation?; pbUpdate; end
  end
end

After all these changes it works like a charm. The script to start the battle is for example
pbSimulatedTrainerBattle(pbLoadTrainer(:TRAINER_A,"Aron"),pbLoadTrainer(:TRAINER_B,"Bob"))
Thanks again for the feedback and for your time. I updated the files, so any further downloads should work out of the box.
 

Specimen1334

Rookie
Member
Joined
Aug 2, 2022
Posts
4
Hey, I was wondering if this was going to be updated to v20.1
I have been wanting to have 2 NPCs battle each other, just as a simulated battle.
So essentially, trainer A walks in the building, reaches trainer B, stops for a few seconds. If they win the battle they keep walking, if they lose the battle they turn around and walk out.
I don't need to be able to see the battle, just for it to actually take place.
I was hoping you might be able to provide some assistance?
 

Hollow_Ego

Cooltrainer
Member
Joined
May 19, 2018
Posts
116
Hey, I was wondering if this was going to be updated to v20.1
I have been wanting to have 2 NPCs battle each other, just as a simulated battle.
So essentially, trainer A walks in the building, reaches trainer B, stops for a few seconds. If they win the battle they keep walking, if they lose the battle they turn around and walk out.
I don't need to be able to see the battle, just for it to actually take place.
I was hoping you might be able to provide some assistance?
Hey,

sorry there are no plans on updating any of my scripts.

What you describe would also require more effort to implement, since you have to do all the battle logic without the screen. I personally don't think it's worth the effort to simulate something the player can't see. It would be much easier to decide the winner based on random chance. You could still derive that chance based on the trainers teams or make it a "best out of 3 coin flips" type of thing.
 
Top