Extended Troops (convert from VX Ace to VX?)

● ARCHIVED · READ-ONLY
Started by lordskylark 7 posts View original ↗
  1. I found this very helpful code written in RGSS3 and couldn't find anything else like it for regular VX. I tried it and it definitely doesn't work for VX (some VX ACE code I have used and it worked fine, or needed very slightly tweaking), but this one I cannot get to work. Is there anyone who would be willing to make it useable for regular VX? Also in the process, could someone make it so that it does not use enemy names to call up enemies (i.e. <name=slime>), but instead uses enemy ID#, since I have several enemies with the exact same name.

    The help would be very much appreciated.

    Thanks,

    Andy



    Code:
    =begin
    ================================================================================
    Extended Troops
    Author: Night Runner, Tsukihime
    Version: 0.2
    Date: May 1, 2012
    --------------------------------------------------------------------------------
    ** Change log
    0.2 May 7, 2012
    -introduced bias and deviation
    -added "final" option
    -added "include" option
    0.1 May 1, 2012
    -initial release
    ================================================================================
    ** Instructions
    
    This system extends the enemy troop management system by allowing you to
    specify more options for a particular troop. It uses probabilistic methods
    to generate enemies depending on the given inputs.
    
    The system provides a set of options that you can set in a game troop's
    event list using comments. You start by specifying the number of enemies
    <numenemies=1>
    
    You can also specify min/max ranges instead of a fixed number
    <minenemies=1, maxenemies=3>
    
    Additionally, you may bias the number generator towards a specific
    range of numbers using a specified bias and optionally a deviance
    <minenemies=2, maxenemies=7, bias=3, deviance=1>
    
    Then you specify which enemies should be randomly selected. The engine
    will pick an arbitrary number of enemies until it has satisfies the number
    of enemies that was generated from above.
    
    The simplest way to specify an enemy is to provide its name
    <name=slime>
    
    You may specify different enemies to be chosen by adding a new line for each
    <name=slime>
    <name=wisp>
    <name=werewolf>
    
    Additional options can be added to provide more interesting results.
    For example, if you want one enemy to statistically occur more often, you
    can specify the weight
    <name=slime, weight=100>
    <name=wisp, weight=10>
    This would mean wisps will occur less frequently than slimes
    There are a variety of options that you can choose as well. They are
    described below.
    
    If you run out of comment space, simply create a new comment and continue
    from there. All entries must appear together though (no other events in
    in between)
    
    --------------------------------------------------------------------------------
    ** Options
    
    All options will be comma-separated within an entry.
    <option1=val, option2, option3=val, option4, ... >
    
    == Troop size options ==
    
    * NumEnemies=integer
    Number of enemies that can appear
    
    * MinEnemies=integer
    Minimum number of enemies that can appear.
    
    * MaxEnemies=integer
    Maximum number of enemies that can appear.
    
    * Bias=integer
    
    * Deviation=integer
    
    == Enemy entry options ==
    
    * Name=name
    The name of the enemy that should appear. Same as the name in the
    database
    
    * Weight=integer
    Adjusts how frequent the enemy will appear compared to other enemies
    
    * Spots=integer
    How many "spots" an enemy takes up. This represents the size of an enemy.
    An enemy with "spots=2" means that they count as 2 enemies and so if your
    numenemies is 5, you can only have 3 more.
    
    * PackOnly
    This forces the troop to contain only that enemy.
    
    * PackSize=integer
    Enemies will be added in groups of the specified integer. So if PackSize=2,
    then the enemy will always appear in pairs, assuming there is enough room
    in the
    
    * Avoid="name1;name2;..."
    The enemies that are listed in this option will not appear with the troop.
    The specified enemies must have entries specified.
    
    * Include="name1;name2;..."
    The enemies that are listed in this option will automatically appear with
    the enemy. The specified enemies must have entries specified.
    
    * Final
    If this enemy is selected, the engine will proceed to create the troop even
    if the maximum size has not been met
    ================================================================================
    =end
    
    module NR_EncounterSystem_Config
    
    #name of the options. You can change all of these if you want.
    MaxEnemiesText = 'maxenemies'
    MinEnemiesText = 'minenemies'
    NumEnemiesText = 'numenemies'
    BiasText = 'bias'
    DeviationText = 'deviation'
    NameText = 'name'
    WeightText = 'weight'
    MaxText = 'max'
    SpotsText = 'spots'
    PackSizeText = 'packsize'
    AvoidText = 'avoid'
    PackOnlyText = 'packonly'
    FinalText = 'final'
    IncludeText = 'include'
    
    Delimiter = ';'
    end
    
    #================================================================================
    # Rest of the script
    #================================================================================
    module NR_EncounterSystem_Config
    
    DefaultWeight = 100
    DefaultMin = 1
    DefaultMax = 8
    DefaultDeviation = 2
    DefaultSpots = 1
    DefaultPackOnly = false
    DefaultPackSize = 1
    DefaultAvoid = []
    DefaultFinalEnemy = false
    DefaultInclude = []
    
    MaxEnemiesRegex = /#{MinEnemiesText}\s*\=\s*((\d)+)/
    MinEnemiesRegex = /#{MaxEnemiesText}\s*=\s*((\d)+)/
    NumEnemiesRegex = /#{NumEnemiesText}\s*=\s*((\d)+)/
    BiasRegex = /#{BiasText}\s*=\s*((\d)+)/
    DeviationRegex = /#{DeviationText}\s*=\s*((\d)+)/
    NameRegex = /#{NameText}\s*=\s*([^,]*),/
    WeightRegex = /#{WeightText}\s*=\s*([^,]*),/
    MaxRegex = /#{MaxText}\s*=\s*([^,]*),/
    SpotsRegex = /#{SpotsText}\s*=\s*([^,]*),/
    PackSizeRegex = /#{PackSizeText}\s*=\s*([^,]*),/
    AvoidRegex = /#{AvoidText}\s*=\s*([^,]*),/
    PackOnlyRegex = /#{PackOnlyText}\s*(=\s*([^,]*)),/
    FinalRegex = /#{FinalText}\s*,/
    IncludeRegex = /#{IncludeText}\s*=\s*([^,]*),/
    end
    
    #==============================================================================
    # ** Game_Troop
    #------------------------------------------------------------------------------
    # Modified to have random battlers.
    #==============================================================================
    
    class Game_Troop
    #--------------------------------------------------------------------------
    # * Include Modules
    #--------------------------------------------------------------------------
    include NR_EncounterSystem_Config
    #--------------------------------------------------------------------------
    # * Get Troop Objects
    #--------------------------------------------------------------------------
    def troop
    @troops
    end
    #--------------------------------------------------------------------------
    # * Setup
    #--------------------------------------------------------------------------
    alias nr_encounter_system_setup setup unless $@
    def setup(troop_id)
    setup_enemies(troop_id)
    nr_encounter_system_setup(troop_id)
    end
    #--------------------------------------------------------------------------
    # * Setup
    #--------------------------------------------------------------------------
    def setup_enemies(troop_id)
    # Get the enemy troop
    @troops = $data_troops[troop_id]
    # Check if the first command on the first page is a comment
    get_num_enemies
    return if @num_enemies <= 0
    p "Maximum number of enemies: #{@num_enemies}"
    # Parse possible enemies
    @enemies = []
    @total_weighting = 0
    parse_possible_enemies
    
    @members = []
    @members_size = 0
    generate_enemies
    
    create_enemy_troop
    end
    #--------------------------------------------------------------------------
    # * Just a biased sample
    #--------------------------------------------------------------------------
    def biased_sample(range, bias, dev)
    integers = range.to_a
    (bias-dev..bias+dev).each {|n| integers << n}
    integers.sample
    end
    #--------------------------------------------------------------------------
    # * Generate random number of enemies
    #--------------------------------------------------------------------------
    def generate_number(high, low, bias, deviation)
    # introduce a bias towards a certain range of numbers
    if bias
    num = biased_sample(low..high, bias, deviation)
    else
    num = Random.rand(high + 1 - low) + low
    end
    return num
    end
    #--------------------------------------------------------------------------
    # * Get Number of Enemies
    #--------------------------------------------------------------------------
    def get_num_enemies
    if @troops.pages[0].list[0].code == 108
    # Get the text in the comment
    @text = ""
    index = 0
    begin
    @text += @troops.pages[0].list[index].parameters[0].downcase
    index += 1
    end while [108, 408].include? @troops.pages[0].list[index].code
    # Get the number of enemies (do nothing if not stated)
    if @text.include?(MaxEnemiesText)
    min_enemies = @text.scan(MaxEnemiesRegex)[0]
    max_enemies = @text.scan(MinEnemiesRegex)[0][0].to_i
    bias = @text.scan(BiasRegex)[0][0].to_i
    deviation = @text.scan(DeviationRegex)[0]
    
    min_enemies = min_enemies == nil ? DefaultMin : min_enemies[0].to_i
    deviation = deviation == nil ? DefaultDeviation : deviation[0].to_i
    
    @num_enemies = generate_number(max_enemies, min_enemies, bias, deviation)
    elsif @text.include?(NumEnemiesText)
    @num_enemies = @text.scan(NumEnemiesRegex)[0][0].to_i
    else
    @num_enemies = -1
    end
    end
    end
    #--------------------------------------------------------------------------
    # * Parse Possible Enemies
    #--------------------------------------------------------------------------
    def parse_possible_enemies
    # Parse the enemies
    for line in @text.split(/<([^<>]*)>/).map { |s| s + ',' }
    next if not line.include?(NameText)
    name = line.scan(NameRegex)[0][0]
    weight = line.scan(WeightRegex)[0]
    weight = weight == nil ? DefaultWeight : weight[0].to_i
    @total_weighting += weight
    max = line.scan(MaxRegex)[0]
    max = max == nil ? DefaultMax : max[0].to_i
    spots = line.scan(SpotsRegex)[0]
    spots = spots == nil ? DefaultSpots : spots[0].to_i
    packsize = line.scan(PackSizeRegex)[0]
    packsize = packsize == nil ? DefaultPackSize : packsize[0].to_i
    avoid = line.scan(AvoidRegex)[0]
    avoid = avoid == nil ? DefaultAvoid : avoid[0].split(Delimiter)
    packonly = line.scan(PackOnlyRegex)[0]
    packonly = packonly == nil ? DefaultPackOnly : true
    final = line.scan(FinalRegex)[0]
    finalenemy = final == nil ? DefaultFinalEnemy : true
    include = line.scan(IncludeRegex)[0]
    include = include == nil ? DefaultInclude : include[0].split(Delimiter)
    enemy = {
    :name => name,
    :weight => weight,
    :max => max,
    :spots => spots,
    :packsize => packsize,
    :avoid => avoid,
    :packonly => packonly,
    :finalenemy => finalenemy,
    :include => include,
    }
    @enemies << enemy
    end
    end
    #--------------------------------------------------------------------------
    # * Generate Enemies Array
    #--------------------------------------------------------------------------
    def generate_enemies
    # Generate the enemies
    @max_wait_loops = 10
    loops_since_member_added = 0
    begin
    loops_since_member_added += 1
    enemy_weight = Random.rand(@total_weighting + 1) + 1
    for enemy in @enemies
    enemy_weight -= enemy[:weight]
    if (enemy_weight <= 0) and (can_add_enemy?(enemy))
    # If this is a pack enemy, remove the rest from the enemy group
    if enemy[:packonly]
    for e in @enemies
    if e != enemy
    @total_weighting -= e[:weight]
    e[:weight] = -1
    end
    end
    end
    # Add the enemy to the party
    loops_since_member_added = 0
    add_enemy(enemy)
    # Add the enemy's allies
    for ally in enemy[:include]
    enemy = @enemies.find { |en| en[:name] == ally }
    add_enemy(enemy)
    end
    if enemy[:finalenemy] == true
    loops_since_member_added = @max_wait_loops
    end
    end
    end
    end while (@members_size < @num_enemies) and
    (loops_since_member_added < @max_wait_loops)
    
    #shuffle them up
    @members.shuffle
    end
    #--------------------------------------------------------------------------
    # * Can Add Enemy?
    #--------------------------------------------------------------------------
    def can_add_enemy?(enemy)
    # Skip is appropriate
    return false if enemy[:weight] < 0
    # Get the number of enemy spots for this enemy
    en_spots = enemy[:spots] * enemy[:packsize]
    # Skip if this will make too many enemies in the party
    return false if @members_size + en_spots > @num_enemies
    # Check if this will make too many of this enemy
    num_this_enemy = @members.count(enemy)
    return false if num_this_enemy > enemy[:max]
    # Skip this enemy if it's avoid is in the members list
    return false if not (@members & enemy[:avoid]).empty?
    # Skip if packonly and other enemies are in the array
    has_other_members = @members.select { |en| enemy[:name] != en }
    return false if (enemy[:packonly]) and not (has_other_members.empty?)
    # Otherwise, it can be part of the party.
    return true
    end
    #--------------------------------------------------------------------------
    # * Add Enemy
    #--------------------------------------------------------------------------
    def add_enemy(enemy)
    @members += [enemy[:name]] * enemy[:packsize]
    @members_size += enemy[:spots] * enemy[:packsize]
    if @members.count(enemy[:name]) >= enemy[:max]
    @total_weighting -= enemy[:weight]
    enemy[:weight] = -1
    end
    end
    #--------------------------------------------------------------------------
    # * Create Enemy Troop
    #--------------------------------------------------------------------------
    def create_enemy_troop
    
    # Create the troops array
    @troops.members = []
    for index in 0...@members.size
    enemy = @members[index]
    enemy_ID = $data_enemies.select { |en|
    next if en.nil?; enemy == en.name.downcase }[0].id
    troop_member = RPG::Troop::Member.new
    troop_member.enemy_id = enemy_ID
    @troops.members << troop_member
    end
    reorganise_troops_positions
    end
    #--------------------------------------------------------------------------
    # * Reorganise Troops Positions
    #--------------------------------------------------------------------------
    def reorganise_troops_positions
    num_members = @troops.members.size
    for index in 0...num_members
    troop_member = @troops.members[index]
    enemy_width = 128
    enemy_height = 96
    max_across = Graphics.width / enemy_width
    left = (Graphics.width - [num_members, max_across].min * enemy_width) / 2
    troop_member.x = left + (index % max_across) * enemy_width
    troop_member.y = 280 - (index / max_across) * enemy_height
    end
    end
    end
    
    
    
    #==============================================================================
    # ** End of Script.
    #==============================================================================
  2. In theory the script sounds useful but in practice the script is very hard to use because my statistics theory is horrible and I can't come up with a way to properly calculate all of the things.
  3. Even if the statistics are off -- it still makes it so that you don't have to set up as many battle formations/combinations, etc.

    Would it be that complicated to make it work in regular RMVX?
  4. It shouldn't, since it's just adding some methods to Game_Troop.

    Which I like because the script is isolated to a single class.

    There might be some Ace specific references but you just need to deal with them one at a time...
  5. I've moved this thread to RGSS2 Script Requests. Please be sure to post your threads in the correct forum next time. Thank you.
  6. That's the thing -- I'm unfortunately deficient in the programming language as of right now. I'm not sure why it didn't work, but it doesn't work for some reason. I tried to change around some things, but I'm really not sure what I am looking for.
  7. Well the main problem is that not all of the things available in RGSS3 is available in RGSS2.

    Random module is not available.

    Array.shuffle doesn't appear to be available.

    Array.count doesn't seem to be available.

    Seriously what kind of libraries did RGSS2 scripters have to work with.