How to write unison skill/item scripts

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
This post aims to share my understanding about unison skill/item scripts and explore some ways to write some of them designed for respective battle systems.

Unison skill/item scripts are generally heavily dependent on the action input and execution mechanisms of the battle systems they've to work with, so it's incredibly unrealistic, if even possible at all, to write an unison skill/item script that works on multiple battle systems that all have extremely different action input and execution mechanisms.

Therefore, you're assumed to have at least:

- Decent battle scripting proficiency(Experienced scripters having written dozens of useful scripts and solid understanding of the battle related parts of the exposed default RMVXA scripts)

- Solid understanding of the battle systems you want your unison skill/item scripts to work with(having written such battle systems will be a huge bonus here :) )

Before discussing how they can be written, however, I've to clarify what unison skill/items are first.

Clarifications

The basic definition of an unison skill/item is one needing more than 1 battler to cast simultaneously and they all have to pay its costs. But afaik, there are at least 2 types of unison skill/items:

1. A battler picks an unison skill/item using x action slots for each unison battler, and all other unison battler reserves x action slots for that picked unison skill. They all pay the same unison skill/item costs.

Example: DoubleX RMVXA Unison Item

2. Each unison battler picks a skill/item, and if the combination of all those skills/items meets the requirement of triggering an unison skill/item, that unison skill/item will be triggered by one of those unison battlers instead. They either pay the same unison skill/item costs, or pay their own picked skill/item's costs.

Example: Basic Combo Attacks

As only 1 battler can execute an action at a time(unless you're gifted enough to break this limitation in Scene_Battle based battle systems), any unison skill/item has only 1 unison invoker and all the other unison battlers are unison invokees. Only the unison invoker will execute the unison skill/item.

In the 1st type, the unison invoker is always the one picking the unison skills; In the 2nd type, the unison invoker will be picked among all unison battlers according to rules set by the unison skill/item scripts.
Right now I'll only talk about the 1st type unison skill/item scripts that work with the default RMVXA battle system, and only non autobattle/confusion actor unison skills/items will be discussed. I might talk about working with other battle systems later, but for enemy unison skills/items, it's still just way too hard for me to figure out how to solve that(the hardest part for me is the enemy unison AI) XD

1st type non autobattle/confusion actor unison skills/items in the default battle system

You're assumed to have a solid understanding to the default RMVXA battle flow implementations when reading this part.

1. Battle modification requirements

Action Execution Changes

1. As only the unison invoker will execute the unison skill/item, all the other unison invokees only need to pay the unison skill/item costs after executing that unison skill/item.

2. To clearly show all the unison battlers of the unison skill/item when it's executing, the log window should show all their names.

Action Usability Changes

1. As all unison battlers need to be able to use the unison skill/item while only the unison invoker actually uses it, the action usability check of the unison invoker upon both inputting and executing that unison skill/item needs to check all unison battlers' usability of that unison skill/item.

Action Input Changes

1. Right after an unison invoker finished inputting the unison skill/item, all other unison invokees of that unison skill/item needs to reserve an action slot for that unison skill/item.

2. Right after an action slot of an unison invoker's been replaced the previous unison skill/item with a new skill/item(or right after an previously inputted action slot with an unison skill/item's pointed to), all other unison invokees' reserved action slots for that unison skill/item need to be "freed".

3. If proceeding to the next action slot would point to a reserved one for an unison skill/item, the next action slot of that reserved one, if any(or the 1st action slot of the next inputable actor if the last action slot's reached), should be pointed to instead. Repeat until there's no more next action slots(then the Action Input Phase should be ended) or the next one isn't reserved for unison skills/items.

4. If proceeding to the prior action slot would point to a reserved one for an unison skill/item, the prior action slot of that reserved one, if any(or the last action slot of the prior inputable actor if the 1st action slot's reached), should be pointed to instead. Repeat this until there's no more prior action slots(then the party command window should be shown) or the prior one isn't reserved for unison skills/items.
2. Battle modification implementations

Action Execution Changes

Both are easy and simple.

For the 1st change, when the unison invoker pays the unison skill/item costs, asks all other unison invokees to do so too. For instance(Upcoming version of DoubleX RMVXA Unison Item):

#----------------------------------------------------------------------------| # Alias method: use_item | #----------------------------------------------------------------------------| alias unison_item_use_item use_item def use_item(item) # Rewritten to pay unison skill cost unless item.is_a?(RPG::Skill) && item.unison_item return unison_item_use_item(item) end item.unison_actor_id.each { |a_id| $game_actors[a_id].pay_skill_cost(item) } item.effects.each { |effect| item_global_effect_apply(effect) } # end # use_item
The original use_item will be called instead if it's not an unison skill/item, otherwise all unison battlers will pay that unison skill/item's costs.

For the 2nd change, when the log window displays the use of an unison skill/item, shows all unison battlers' names instead of just the unison invokee's. For instance(Upcoming version of DoubleX RMVXA Unison Item):

#----------------------------------------------------------------------------| # Alias method: display_use_item | #----------------------------------------------------------------------------| alias unison_item_display_use_item display_use_item def display_use_item(subject, item) # Rewritten to display unison actors while using unison skills or items if DoubleX_RMVXA::Unison_Item::SHOW_UNISON_ACTOR && item.unison_item unison_actor_list = "" unison_actor_counter = 0 item.unison_actor_id.each { |actor_id| unison_actor_counter += 1 if unison_actor_counter > 1 && unison_actor_counter < item.unison_actor_id.size unison_actor_list += ", " elsif item.unison_actor_id.size > 1 && unison_actor_counter == item.unison_actor_id.size unison_actor_list += " and " end unison_actor_list += $game_actors[actor_id].name } if item.is_a?(RPG::Skill) add_text(unison_actor_list + item.message1) unless item.message2.empty? wait add_text(item.message2) end else add_text(sprintf(Vocab::UseItem, unison_actor_list, item.name)) end else unison_item_display_use_item(subject, item) end # end # display_use_item
The original display_use_item will be called instead if it's not an unison skill/item, otherwise all unison battlers' names will be stored in unison_actor_list which is used in add_text.

Action Usability Changes

This one's a bit challenging, but if you've a solid understanding of how action usability checks in the default RMVXA battle system works, you should've little trouble implementing this change.

For instance(Upcoming version of DoubleX RMVXA Unison Item):

#----------------------------------------------------------------------------| # Alias method: usable? | #----------------------------------------------------------------------------| alias unison_item_usable? usable? def usable?(item) # Added to check if unison skills or items are usable if actor? && item && (item.is_a?(RPG::UsableItem)) && item.unison_item return false unless item.unison_actor_id.any? { |a_id| a_id == id } if item.is_a?(RPG::Skill) item.unison_actor_id.each { |actor_id| return false unless (actor = $game_actors[actor_id]).battle_member? return false unless actor.inputable? && actor.skill_exist?(item.id) return false unless actor.skill_conditions_met?(item) } return true elsif item.is_a?(RPG::Item) && item_conditions_met?(item) item.unison_actor_id.each { |actor_id| return false unless (actor = $game_actors[actor_id]).battle_member? return false unless actor.inputable? } return true else return false end end # unison_item_usable?(item) end # usable?
The original usable? will be called if it's not an unison skill/item.

It shouldn't be usable if:

- It's not picked by an unison battler

- Not all unison actors are in the battle

- Not all unison battlers are inputable

If it's a skill, then it shouldn't be usable as well if:

- Not all unison battlers have that unison skill/item

- Not all unison battlers meet its requirements

Action Input Changes

This one's the main dish in this post, as it's quite tough, and much harder than the other changes. If you don't have a solid understanding of how the action input phase of the default RMVXA battle system works, you'd likely be doomed here lol

Anyway, you've to know the below 2 facts to have a reasonable chance to implement the changes:

1. There are 3 action slot types that are of our interests here - Ordinary action slots(having ordinary skills/items or not inputted anything not due to being reserved), unison action slots(having unison skills/items; unison invoker only) and reserved action slots(for unison skills/items; unison invokees only).

2. Recall that all action slots of all inputable actors are linked by a doubly linked list or an analogous data structure, and the item part of any action slot can't be cleared but only replaced by new ones in the action input phase. Combining with all the needed action usability and input changes, it can be deduced that the unison invoker's index is always smaller than every other unison invokee's one(thus the 1st inputable actor will never be an unison invokee).

The above 2 facts are fundamental to the below Dual Stack Algorithm and Dual Variable Algorithm. They've to be used together in order to work.

For the Dual Stack Algorithm:

1. Uses 2 new stacks to trace the action slots - 1 for ordinary/unison ones(input stack), and another for reserved ones(reserved stack). They should be initially empty arrays.

2. Right after inputting an ordinary skill/item, pushes its action slot into the input stack, and an empty list into the reserved one.

3. Right after inputting an unison skill/item, pushes its action slot into the input stack, and its associated unison battler id list into the reserved one.

4. Right before pointing to a previously inputted action slot, pops both the input and reserved stack once.

5. Both stacks should be cleared after ending the action input phase.

For the Dual Variable Algorithm:

1. Uses 2 variables to trace the number of inputted(existing @action_input_index) and reserved action slots(new @reserve_act) respectively for each actor. The latter should be 0 when new action slots are made.

2. Right after an actor inputs a skill/item, increases @action_input_index of that actor by 1(default behavior).

3. Right after allocating a reserved action slot for an actor(3. of the Dual Stack Algorithm), increases @reserve_act of that actor by 1.

4. Right before pointing to a previously inputted action slot(for any actor), decreases @action_input_index of the actor owning that inputted action slot by 1(default behavior) and @reserve_act of all actors included by the associated unison battler id list, if any, by 1(or does nothing if it's an empty array instead).

5. An actor shouldn't be inputable if @action_input_index + @reserve_act = the number of action slots(so the sum of the formers should never be greater than the latter).

The below explains why Dual Stack Algorithm and Dual Variable Algorithm will work when used together(you'll have to have a solid understanding of how the actor inputable check of the default RMVXA battle system works to understand these explanations):

1. All the reserved action slots of an actor are always that actor's last action slots, and the 1st inputable actor will never have any reserved action slots.

2. For the 1st needed change, each unison invokee reserves 1 action slot by increasing @reserve_act by 1. As the number of action slots stays the same in the same action input phase and the maximum value of @action_input_index, which is the number of action slots - @reserve_act, indicates the maximum number of inputtable action slots(default behavior), each unison invokee now has 1 less inputable action slot.

3. For the 2nd needed change, when a previously inputted unison action slot's pointed to, the reserved stack will pop the associating unison battler id list, and all actors included by that list will decrease @reserve_act by 1, effectively increasing the maximum value of @action_input_index by 1 and thus freeing their reserved action slots.

4. For the 3rd needed change, when a reserved action slot would be pointed to, it'd mean all the next action slots are reserved and @action_input_index + @reserve_act = the number of action slots, making the actor not inputable. As the "next pointer"(except the tail one) always points to inputable actor's action slots, it'll point to the 1st action slot of the next inputable actor instead.

5. For the 4th needed change, when a reserved action slot would be pointed to, both the input and reserved stack will be popped.

If @action_input_index of the would be selected actor is 0, it'll be untouched as that actor has no inputted action slots at all, meaning that actor's not inputable. As the "previous pointer"(except the head one) always points to inputable actor's action slots,the last action of the prior actor would be pointed to instead and this check will be repeated until an inputable actor's found.

Otherwise @action_input_index of the would be selected actor will be decreased by 1, making that actor inputable. The last inputable action slot of that actor will be pointed to(default behavior).

The below is an example(Upcoming version of DoubleX RMVXA Unison Item) using the core strategies behind the Dual Stack Algorithm:

class Scene_Battle < Scene_Base #----------------------------------------------------------------------------| # Alias method: next_command | #----------------------------------------------------------------------------| alias unison_item_next_command next_command def next_command # Added to add the actor id and unison actor id list to non_inputable_actor # and unison_actor stacks respectively if BattleManager.actor && @unison_skill add_input_actor_id(BattleManager.actor.id) if @unison_skill.unison_item add_unison_actor_id_list(@unison_skill.unison_actor_id) else add_unison_actor_id_list([]) end end # unison_item_next_command end # next_command #----------------------------------------------------------------------------| # Alias method: prior_command | #----------------------------------------------------------------------------| alias unison_item_prior_command prior_command def prior_command # Rewritten to clear the last element of non_inputable_actor and # unison_actor stacks clear_input_actor_id unison_item_prior_command clear_unison_actor_id_list # end # prior_command #----------------------------------------------------------------------------| # Alias method: command_attack | #----------------------------------------------------------------------------| alias unison_item_command_attack command_attack def command_attack # Added to store the item selected by the actor @unison_skill = $data_skills[BattleManager.actor.attack_skill_id] # unison_item_command_attack end # command_attack #----------------------------------------------------------------------------| # Alias method: command_guard | #----------------------------------------------------------------------------| alias unison_item_command_guard command_guard def command_guard # Added to store the item selected by the actor @unison_skill = $data_skills[BattleManager.actor.guard_skill_id] # unison_item_command_guard end # command_guard #----------------------------------------------------------------------------| # Alias method: on_skill_ok | #----------------------------------------------------------------------------| alias unison_item_on_skill_ok on_skill_ok def on_skill_ok # Added to store the item selected by the actor @unison_skill = @skill_window.item # unison_item_on_skill_ok end # on_skill_ok #----------------------------------------------------------------------------| # Alias method: on_item_ok | #----------------------------------------------------------------------------| alias unison_item_on_item_ok on_item_ok def on_item_ok # Added to store the item selected by the actor @unison_skill = @item_window.item # unison_item_on_item_ok end # on_item_ok #----------------------------------------------------------------------------| # Alias method: turn_start | #----------------------------------------------------------------------------| alias unison_item_turn_start turn_start def turn_start # Added to reset non_inputable_actor and unison_actor stacks reset_input_actor_id reset_unison_actor_id_list # unison_item_turn_start end # turn_start #----------------------------------------------------------------------------| # New method: add_input_actor_id | #----------------------------------------------------------------------------| def add_input_actor_id(actor_id) @input_actor_id ||= [] @input_actor_id << actor_id (actor = $game_actors[actor_id]).input_actor -= 1 actor.unison_next_input end # add_input_actor_id #----------------------------------------------------------------------------| # New method: clear_input_actor_id | #----------------------------------------------------------------------------| def clear_input_actor_id if @input_actor_id && @input_actor_id.size > 0 $game_actors[@input_actor_id[-1]].unison_input.clear $game_actors[@input_actor_id[-1]].unison_prior_input $game_actors[@input_actor_id[-1]].input_actor += 1 @input_actor_id.delete_at(@input_actor_id.size - 1) end end # clear_input_actor_id #----------------------------------------------------------------------------| # New method: reset_input_actor_id | #----------------------------------------------------------------------------| def reset_input_actor_id if @input_actor_id && @input_actor_id.size > 0 @input_actor_id.each { |actor_id| (actor = $game_actors[actor_id]).input_actor = actor.unison_action_times } end @input_actor_id = [] end # reset_input_actor_id #----------------------------------------------------------------------------| # New method: add_unison_actor_id_list | #----------------------------------------------------------------------------| def add_unison_actor_id_list(actor_id_list) unison_actor_id_list = [] actor_id_list.each { |actor_id| unison_actor_id_list << actor_id if actor_id != BattleManager.actor.id } @unison_actor_id_list ||= [] @unison_actor_id_list.push(unison_actor_id_list) if unison_actor_id_list.size > 0 unison_actor_id_list.each { |actor_id| $game_actors[actor_id].unison_actor -= 1 if $game_actors[actor_id] } end end # add_unison_actor_id_list #----------------------------------------------------------------------------| # New method: clear_unison_actor_id_list | #----------------------------------------------------------------------------| def clear_unison_actor_id_list if @unison_actor_id_list && @unison_actor_id_list.size > 0 if @unison_actor_id_list[-1].size > 0 @unison_actor_id_list[-1].each { |actor_id| $game_actors[actor_id].unison_actor += 1 if $game_actors[actor_id] } end @unison_actor_id_list.delete_at(@unison_actor_id_list.size - 1) end end # clear_unison_actor_id_list #----------------------------------------------------------------------------| # New method: reset_unison_actor_id_list | #----------------------------------------------------------------------------| def reset_unison_actor_id_list if @unison_actor_id_list && @unison_actor_id_list.size > 0 @unison_actor_id_list.each { |actor_id_list| next if actor_id_list.size <= 0 actor_id_list.each { |actor_id| next unless actor = $game_actors[actor_id] actor.unison_actor = actor.unison_action_times } } end @unison_actor_id_list = [] end # reset_unison_actor_id_listend # Scene_Battle
The below is an example(Upcoming version of DoubleX RMVXA Unison Item) using the core strategies behind the Dual Variable Algorithm:

#----------------------------------------------------------------------------| # Alias method: inputable? | #----------------------------------------------------------------------------| alias unison_item_inputable? inputable? def inputable? # Rewritten to set inputable as considering actors using skills or items or # being used in unison skills or items also (!SceneManager.scene_is?(Scene_Battle) || @input_actor + @unison_actor > @actions.size) && unison_item_inputable? # end # inputable?
Code:
  #----------------------------------------------------------------------------|  #  (v1.00d+)Alias method: make_actions                                       |  #----------------------------------------------------------------------------|  alias unison_item_make_actions make_actions  def make_actions    unison_item_make_actions    # Added to set unison_actor and non_inputable    @input_actor = @unison_actor = @actions.size    #  end # make_actions
Code:
  #----------------------------------------------------------------------------|  #  (v1.00d+)New method: unison_action_times                                  |  #----------------------------------------------------------------------------|  def unison_action_times    @actions ? @actions.size : 0  end # unison_action_times
Code:
  #----------------------------------------------------------------------------|  #  (v1.00d+)Alias method: clear_actions                                      |  #----------------------------------------------------------------------------|  alias unison_item_clear_actions clear_actions  def clear_actions    unison_item_clear_actions    # Added to initialize @unison_input_index    @unison_input_index = 0    #  end # clear_actions
Code:
  #----------------------------------------------------------------------------|  #  (v1.00d+)New method: unison_next_input                                    |  #----------------------------------------------------------------------------|  def unison_next_input    @unison_input_index += 1 if @unison_input_index < @actions.size - 1  end # unison_next_input  #----------------------------------------------------------------------------|  #  (v1.00d+)New method: unison_prior_input                                   |  #----------------------------------------------------------------------------|  def unison_prior_input    @unison_input_index -= 1 if @unison_input_index > 0  end # unison_prior_input


That's all for now. I hope this topic can help you better grasp how unison skills/item scripts can be written. Again, later I might write how to write them for other battle systems(probably including Yanfly Engine Ace - Ace Battle Engine), and how to write enemy unison skills/items scripts when I can finally figure it out myself. For skilled unison skills/items script developers, feel free to point out any mistake I made :D
 
Last edited by a moderator:

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
1st type non autobattle/confusion actor unison skills/items in Yanfly Engine Ace - Ace Battle Engine

This one's so complicated and convoluted that you're assumed to have:

- A thorough comprehension to the battle flow of Yanfly Engine Ace - Ace Battle Engine

- Advanced battle related scripting proficiency(scripting veteran having written at least 1 advanced complex battle related script and a thorough comprehension to the exposed battle related part of the default RMVXA scripts)

New command: :dir6 calling next_command

YEA-BattleEngine aliased create_actor_command_window to set this new handler:

#-------------------------------------------------------------------------- # alias method: create_actor_command_window #-------------------------------------------------------------------------- alias scene_battle_create_actor_command_window_abe create_actor_command_window def create_actor_command_window scene_battle_create_actor_command_window_abe @actor_command_window.set_handler:)dir4, method:)prior_command)) @actor_command_window.set_handler:)dir6, method:)next_command)) end
So whenever the actor command window's active, pressing the keys mapping to :dir6 will call next_command directly.

In the default battle system, the only way to reach next_command is to input attack/skills/guard/item, then input targets if the inputted skill/item needs that, and finally next_command will be reached.

If the currently selected action slot's empty or has already inputted a skill/item, it'll always be replaced by the new one during the process of reaching next_command from an active actor command window.

In YEA-BattleEngine, that's not necessarily the case, however, as the new :dir6 command lets players reach next_command from an active actor command window without going through the above "path". Therefore that direct jump can keep the empty or previously inputted skill/item of the currently selected action slot unchanged.

Note that players doesn't have to use this new :dir6 command, meaning it's possible to be never used in some cases. This implies any unison skills/items script that works on YEA-BattleEngine shall also work on the default battle system.

This new command is what makes writing unison skills/items scripts that work with YEA-BattleEngine so exceptionally tough. To me, writing ones that work with the default battle system is like a cakewalk compared to this :D


New challenge raised by the new command

In the default battle system, when the ith action slot of the jth inputable actor's selected, it's certain that all action slots of the 1st to the (j - 1)th inputable actors, and the 1st to the (i - 1)th ones of the jth inputable actor have inputted actions. So if the jth inputable actor's the unison invoker of an unison skill/item, all the 1st to the (i - 1)th actors can never be the unison invokees.

In YEA-BattleEngine, that's not necessarily the case, however. Say the 1st inputable actor has inputted nothing and the 2nd inputable actor's selected. The latter actor inputs an unison skill/item with the former actor as the unison invokee. The below's the new challenge raised:

Now an empty action slot of the former actor has to be reserved for that unison skill/item. When going back to the former actor, that reserved action slot has to be kept reserved and hence skipped and an ordinary empty action slot has to be selected instead. Otherwise, If the former actor inputs skills/items for all his/her/its action slots, the latter actor's unison skill/item will still be there and can still be executed. This violates the fundamental requirement that an unison skill/item needs each unison invokee to reserve 1 action slot to execute it.

When the unison invoker wants to replace that unison skill/item to another unison skill/item needing the exact same unison invokees and they all have no ordinary empty action slots(they'd have 1 each if the former unison skill/item was cleared), the latter unison skill/item won't be usable even if it's supposed to be.
Conditions and constraints to be met

Conditions(From unison skills/items requirements):

1. All unison invokees of an unison skill/item must have at least 1 ordinary empty action slot to make that unison skill/item usable.

2. Right after inputting that unison skill/item, each unison invokee must reserve 1 empty action slot for that unison skill/item; Right after replacing that uniosn skill/item by a new skill/item, all reserved action slots of that unison skill/item must be freed.

3. If the next/prior action slot is reserved for an unison skill/item, find the next/prior action slot of that reserved one that's not reserved. Repeat until one that's not reserved's selected or the party command window/end of action input phase's reached.

Constraints(From YEA-BattleEngine):

1. Previously inputted actions can only be replaced by new ones but shall never be cleared.

2. Going from the current action slot to the next one can be done without replacing the skill/item of the current one.

3. If an unison skill/item can be inputted by an actor at the start of the action input phase, players shouldn't be able to reach a situation where that actor can no longer input that unison skill/item no matter what they do in the same action input phase.
Fundamental conflicts between unison skills/items and YEA-BattleEngine

Suppose there's an unison skill/item having the 1st and 2nd inputable actor as the unison ones. The 1st one inputs nothing and the 2nd one's selected. The 2nd one can now input that unison skill/item as the 1st one has ordinary empty action slots and all the other requirements are met. But instead of just inputting it, the 1st one's selected again and that actor inputted all action slots with skills/items. Now the 2nd one's selected and that actor can no longer input that unison skill/item as the 1st one no longer have any ordinary empty action slots.

The only way to let the 2nd one to input that unison skill/item is to clear at least 1 action slot of the 1st one so that actor will have at least 1 ordinary empty action slot again. Doing so will violate the 1st constraint while not doing so will violate the 3rd constraint, meaning there's a fundamental conflict between unison skills/items and YEA-BattleEngine.
Deciding what to compromise

The aforementioned conflict shows that writing an unison skills/items script needs to compromise either the 1st or the 3rd constraint.

The former will drastically change the YEA-BattleEngine behavior. Now instead of asking each unison invokee to reserve an ordinary empty action slot for an inputted unison skill/item, inputting one will directly clear an action slot for each unison invokee for using that unison skill/item, even if those action slots has already inputted skills/items. Developers/players will always have to be crystal clear on which action slots will be cleared in any given case.

The latter will likely drive developers/players insane. Now instead of simply thinking how to design/utilize the unison skill/items, they'll also always have to be extremely cautious so they'll never end up "locking up" those unison skills/items that are supposed to be usable. To be "absolutely certain", they'll have to assume an unison skill/item with the index of the unison invoker greater than that of an unison invokee will eventually be "locked up" and not usable anymore.

Assuming that unison skills/items script's to be written. Then there are 3 choices: Compromising the 1st constraint, compromising the 3rd one, or letting users choose which to compromise.

Regardless of what's chosen, however, that script should elaborate why such compromise has to be made, otherwise users will likely question its necessity. You should also have a clear vision on the possible impacts on developers, players and even other scripters of each choice before making that design decision.

If the 1st choice's made, that script should elaborate why inputting unison skills/items can end up clearing unison invokees' action slots for using them, and teach users how to determine which action slots will be cleared in any given case.

If the 2nd choice's made, that script should elaborate why unison skills/items can be "locked up" in some cases, and teach users how to determine if an unison skill/item will be "locked up" in any given case.

If the 3rd choice's made, that script should elaborate both compromises. It should also state that users can't switch from compromising the 1st constraint to compromising the 3rd one during the same action input phase.

Bear in mind that each choice will significantly change the compatibility of that script, so as long as you care about it, you should have a clear vision on the possible compatibility issues of each choice before making that design decision.

To me, this design decision is such a harsh dilemma that it alone makes writing such unison skills/items scripts to demand advanced scripting proficiency, as compromising either constraint will likely lead to extremely undesirable situations :)
More advanced algorithms

Regardless of which constraint to compromise, the Dual Stack Algorithm in conjunction with the Dual Variable Algorithm won't work with YEA-BattleEngine, as that combination's based on the fact that the unison invoker's index is always smaller than every other unison invokee's one, which just doesn't hold in YEA-BattleEngine.

Therefore, a more advanced algorithm needs to be used instead. It's harder to understand how and why it works, but is also simpler to implement and use once you understand it.

As any solution that works on YEA-BattleEngine must also work on the default battle system, and the aforementioned design decision will lead to significantly different implementations, I'll only show the algorithm on a higher level, how and why it works on the default battle system, and some example codes below will only work on the default battle system.

The algorithm:

Instead of using 2 new stacks and 1 new variable and 1 existing one, 1 new hash and 1 new variable will suffice:

1. Uses a new hash, @unison_actor_ids, to trace the link between the unison action slots and the id of their unison invokees. Sets it as empty at the start of an action input phase.

2. Uses a new variable, @unison_inputs, for each actor to mark the number of action slots reserved for unison skills/items. Sets it as 0 at the start of an action input phase and negative during the action execution phase respectively.

3. Right after finishing inputting an unison skill/item, registers the array storing the actor's index and action input index as the key of @unison_actor_ids representing the action slot, and stores the array storing the id of all unison invokees as that key's mapped value in @unison_actor_ids. Increases @unison_inputs for each unison invokee by 1.

4. Right before selecting a prior action slot, clears the currently selected action slot.

5. Right after selecting a prior action slot having inputted an unison skill/item, removes the link between that action slot and the id of all unison invokees in @unison_actor_ids, and increases @unison_inputs for each unison invokee by 1.

6. An actor shall never be inputable in battle if @unison_inputs >= the number of action slots.

7. next_command of Game_Actor shall return false If the actor's action input index >= the number of action slots - 1 - @unison_inputs.

8. An unison skill/item shall never be usable if at least 1 unison invokee has no ordinary empty action slots.

How and why it works:

As an unison skill/item can be usable only if all unison invokees has at least 1 ordinary empty action slot to be reserved for that unison skill/item, and an actor's inputable only if not all of the action slots are reserved, unison skill/item usability check and actor inputability check are inherently coupled. Nevertheless, that coupling should be as loose as possible to maximize the chance of making it work on YEA-BattleEngine with any aforementioned design decision. On the other hand, action usability check and actor inputability check are completely separated from paying action costs, so that new algorithm doesn't have to worry about the latter at all.

Recall the action usability change in the default battle system:

1. As all unison battlers need to be able to use the unison skill/item while only the unison invoker actually uses it, the action usability check of the unison invoker upon both inputting and executing that unison skill/item needs to check all unison battlers' usability of that unison skill/item.

Recall the 4 action input changes in the default battle system:

1. Right after an unison invoker finished inputting the unison skill/item, all other unison invokees of that unison skill/item needs to reserve an action slot for that unison skill/item.

2. Right after an action slot of an unison invoker's been replaced the previous unison skill/item with a new skill/item(or right after an previously inputted action slot with an unison skill/item's pointed to), all other unison invokees' reserved action slots for that unison skill/item need to be "freed".

3. If proceeding to the next action slot would point to a reserved one for an unison skill/item, the next action slot of that reserved one, if any(or the 1st action slot of the next inputable actor if the last action slot's reached), should be pointed to instead. Repeat until there's no more next action slots(then the Action Input Phase should be ended) or the next one isn't reserved for unison skills/items.

4. If proceeding to the prior action slot would point to a reserved one for an unison skill/item, the prior action slot of that reserved one, if any(or the last action slot of the prior inputable actor if the 1st action slot's reached), should be pointed to instead. Repeat this until there's no more prior action slots(then the party command window should be shown) or the prior one isn't reserved for unison skills/items.

So any such algorithm must accomplish all these changes in order to work. The below will show that they're all accomplished by that new algorithm:

1. If at least 1 unison invokee has no ordinary empty action slot, it means that actor has none to be reserved for that unison skill/item, thus causing the unison skill/item to be not usable; If that's not the case, all the other usability requirements has already been checked by the previously modified action usability check.

2. Right after an unison invoker finished inputting the unison skill/item, @unison_inputs of all other unison invokees will be increased by 1, causing the maximum value of their action input index, which is the number of action slots - 1 - @unison_inputs, to be decreased by 1, meaning 1 less action slot can be selected from each of them, effectively reserving an action slot from each of them for that unison skill/item.

3. Right after an previously inputted action slot with an unison skill/item's pointed to, the link between that action slot and the id of all unison invokees in @unison_actor_ids will be removed and @unison_inputs for each unison invokee will be decreased by 1, causing the maximum value of their action input index, which is the number of action slots - 1- @unison inputs, to be increased by 1, meaning 1 more action slot can be selected from each of them, effectively freeing the reserved action slots from them for that unison skill/item.

4. If proceeding to the next action slot would point to a reserved one for an unison skill/item, next_command in Game_Actor would return false, causing the next inputable actor to be selected. As all the reserved action slots are always the last action slots, as long as the next actor has at least 1 non reserved action slot, that actor will be inputable if all other inputable conditions are met, and the 1st action slot, which won't be reserved, will be selected as that actor's action input index will be 0.

5. If proceeding to the prior action slot would point to a reserved one for an unison skill/item, it would mean the prior actor's selected as all the reserved action slots are always the last action slots. As long as that actor's at least 1 non reserved action slot, that actor will be inputable if all other inputable conditions are met, and the last non reserved action slot will be selected as that actor's action input index will be the number of action slots - 1 - @unison_inputs.

Example codes(upcoming version of DoubleX RMVXA Unison Skill/Item):

  #----------------------------------------------------------------------------|  #  Alias method: inputable?                                                  |  #----------------------------------------------------------------------------|  alias inputable_unison_item? inputable?  def inputable?    # Rewritten to check if at least 1 action slot isn't reserved    return false unless inputable_unison_item?    return true unless SceneManager.scene_is?(Scene_Battle) && actor?    @unison_inputs < @actions.size    #  end # inputable?  #----------------------------------------------------------------------------|  #  Alias method: usable?                                                     |  #----------------------------------------------------------------------------|  alias usable_unison_item? usable?  def usable?(item)    # Rewritten to check if all unison actors can use the unison skill/item    unless actor? && item && item.is_a?(RPG::UsableItem) && item.unison_item      return usable_unison_item?(item)    end    return false unless item.unison_actor_id.include?(id)    return false unless usable_unison_item?(item)    return unison_skill_usable?(item) if item.is_a?(RPG::Skill)    return unison_item_usable?(item) if item.is_a?(RPG::Item)    false    #  end # usable?  #----------------------------------------------------------------------------|  #  New method: unison_skill_usable?                                          |  #----------------------------------------------------------------------------|  def unison_skill_usable?(item)    battle = SceneManager.scene_is?(Scene_Battle)    (item.unison_actor_id - [id]).each { |actor_id|      actor = $game_actors[actor_id]      return false unless actor.battle_member? && actor.inputable?      return false if battle && actor.actions.select { |a| a.item }.size >=      actor.actions.size - actor.unison_inputs      return false unless actor.skill_conditions_met?(item)      return false unless actor.skills.any? { |s| s == $data_skills[item.id] }    }    true  end # unison_skill_usable?  #----------------------------------------------------------------------------|  #  New method: unison_item_usable?                                           |  #----------------------------------------------------------------------------|  def unison_item_usable?(item)    return false unless item_conditions_met?(item)    (item.unison_actor_id - [id]).each { |actor_id|      actor = $game_actors[actor_id]      return false unless actor.battle_member? && actor.inputable?    }    true  end # unison_item_usable?
Code:
  #----------------------------------------------------------------------------|  #  (v1.01d+)Alias method: setup                                              |  #----------------------------------------------------------------------------|  alias unison_item_setup setup  def setup(actor_id)    unison_item_setup(actor_id)    # Added to initialize the number of reserved action slots    @unison_inputs = 0    #  end # setup  #----------------------------------------------------------------------------|  #  (v1.00d+)Alias method: clear_actions                                      |  #----------------------------------------------------------------------------|  alias unison_item_clear_actions clear_actions  def clear_actions    unison_item_clear_actions    # Added to reset the number of reserved action slots    @unison_inputs = 0    #  end # clear_actions  #----------------------------------------------------------------------------|  #  (v1.01d+)Alias method: next_command                                       |  #----------------------------------------------------------------------------|  alias unison_item_next_command next_command  def next_command    # Added to return false if the next slot is reserved for unison skill/items    return false if @action_input_index >= @actions.size - 1 - @unison_inputs    #    unison_item_next_command  end # next_command
Code:
class Scene_Battle < Scene_Base  #----------------------------------------------------------------------------|  #  (v1.01d+)Alias method: start                                              |  #----------------------------------------------------------------------------|  alias start_unison_item start  def start    start_unison_item    # Added to initialize the unison action linkage hash    @unison_actor_ids = {}    #  end # start  #----------------------------------------------------------------------------|  #  Alias method: next_command                                                |  #----------------------------------------------------------------------------|  alias next_command_unison_item next_command  def next_command    # Added to set the link of the unison action slot to the unison invokees    add_unison_actor_ids if (actor = BattleManager.actor) && actor.input &&    actor.input.item && actor.input.item.unison_item    #    next_command_unison_item  end # next_command  #----------------------------------------------------------------------------|  #  Alias method: prior_command                                               |  #----------------------------------------------------------------------------|  alias prior_command_unison_item prior_command  def prior_command    # Added to clear the currently selected action before selecting the prior    BattleManager.actor.input.clear if BattleManager.actor.input    #    prior_command_unison_item    # Added to clear the unison action linkage and unconfirm the action    clear_unison_actor_ids if BattleManager.actor    #  end # prior_command  #----------------------------------------------------------------------------|  #  Alias method: turn_start                                                  |  #----------------------------------------------------------------------------|  alias turn_start_unison_item turn_start  def turn_start    # Added to reset the links of the unison action slots to the unison invokees    @unison_actor_ids = {}    $game_party.alive_members.each { |mem| mem.unison_inputs = -1 }    #    turn_start_unison_item  end # turn_start  #----------------------------------------------------------------------------|  #  New method: add_unison_actor_ids                                          |  #----------------------------------------------------------------------------|  def add_unison_actor_ids    ids = (actor = BattleManager.actor).input.item.unison_actor_id - [actor.id]    @unison_actor_ids[[actor.index, actor.action_input_index]] = ids    ids.each { |id| $game_actors[id].unison_inputs += 1 }  end # add_unison_actor_ids  #----------------------------------------------------------------------------|  #  New method: clear_unison_actor_ids                                        |  #----------------------------------------------------------------------------|  def clear_unison_actor_ids    a = BattleManager.actor    return unless ids = @unison_actor_ids[[a.index, a.action_input_index]]    @unison_actor_ids.delete([a.index, a.action_input_index])    ids.each { |id| $game_actors[id].unison_inputs -= 1 }  end # clear_unison_actor_idsend # Scene_Battle
Extra Tips:

Clearing previously inputted actions makes sense in the default battle system as they'll be replaced by new ones anyway, but that's just not the case for YEA-BattleEngine as doing so will violate the 1st constraint, so that new algorithm has to be altered to stop doing that part.

Recall that when an unison invoker wants to replace an unison skill/item to another unison skill/item needing the exact same unison invokees and they all have no ordinary empty action slots(they'd have 1 each if the former unison skill/item was cleared), the latter unison skill/item won't be usable even if it's supposed to be.

This can be solved by further decoupling the actor inputability check and action usability check, via using another new variable, @temp_unison_inputs, for each actor.

1. Right after selecting a previously inputted unison skill/item, keep its reserved action slots for all unison invokees reserved, but in the action usability check, pretend that all those reserved action slots are already freed by decreasing @temp_unison_inputs of all unison invokees by 1 right after selecting a previously inputted unison skill/item and checking against @temp_unison_inputs instead of @unison_inputs instead.

2. Right after inputting a new unison skill/item for the same action slot, free the old one's reserved action slots and reserve new action slots for the new ones.


Well, unfortunately, I've been trying to make an unison skill/item script that works with YEA-BattleEngine over an year ago, and uptil now, I still haven't been able to do so, as I just realized the aforementioned design decision dilemma recently and it's just way too harsh for me lol

Edit: I just come up with a possibly better way: Write another addon to YEA-BattleEngine that lets players clear the currently selected action slot by using a new command. That way, the 1st constraints will be removed instead of compromised as now YEA-BattleEngine has been expanded. Now unison skills/items will never be locked up, as players just have to clear at least 1 action slots for each unison invokee so each will have at least 1 ordinary empty action slot to be reserved for those unison skill/items. Of course, writing that addon itself will be quite a challenge, but I still think it's much easier than having to face the aforementioned harsh design decision dilemma.
 
Last edited by a moderator:

DoubleX

Just a nameless weakling
Veteran
Joined
Jan 2, 2014
Messages
1,787
Reaction score
939
First Language
Chinese
Primarily Uses
N/A
(Cont)1st type non autobattle/confusion actor unison skills/items in Yanfly Engine Ace - Ace Battle Engine

Recall that you're assumed to have:

- A thorough comprehension to the battle flow of Yanfly Engine Ace - Ace Battle Engine

- Advanced battle related scripting proficiency(scripting veteran having written at least 1 advanced complex battle related script and a thorough comprehension to the exposed battle related part of the default RMVXA scripts)

I finally come up with these solutions:

DoubleX RMVXA Clear Addon to Yanfly Engine Ace - Ace Battle Engine

DoubleX RMVXA Unison Addon to Yanfly Engine Ace - Ace Battle Engine

The clear addon expands YEA-BattleEngine by letting players explicitly clearing the currently selection action slot, effectively removing this constraint:

- Previously inputted actions can only be replaced by new ones but shall never be cleared.

However, as the main point of adding the new :dir6 command, which calls next_command, is to let players preserve previously inputted or empty action slots, the best compromise I can think of is to add another new command to clear action slots. Clearing action slots can only be done via that command.

Now the aforementioned fundamental conflict between unison skills/items scripts and YEA-BattleEngine can be solved without facing the aforementioned harsh design decision dilemma. Bear in mind that this new command itself is also a compromise(as now users will have to use 1 extra script to bridge YEA-BattleEngine and the unison skills/items scripts and use that new command to explicitly clear the currently selected action slot to unlock the unison skills/items), albeit a much, much less significant one.

The solution implementations

The solution will be based on the improved one for the default RMVXA battle system, but with some modifications.

The algorithm:

1. Uses a new hash, @unison_actor_ids, to trace the link between the unison action slots and the reserved ones of each unison invokee. Sets it as empty at the start of an action input phase.

2. Uses 1 new variable, @unison_inputs, for each actor to be the list of indices of the reserved action slots for unison skills/items in the actor inputability check. Sets it as empty at the start of an action input phase and nil during the action execution phase respectively.

3. Uses another new variable, @temp_unison_inputs, for each actor to mark the number of action slots reserved for unison skills/items in the unison skill/item usability check. Sets it as 0 at the start of an action input phase and negative during the action execution phase respectively.

4. Right after finishing inputting an unison skill/item, removes the link between that action slot and the reserved one of each  unison invokee in @unison_actor_ids, and deletes the reserved one in @unison_inputs for each unison invokee. Then registers the array storing the actor's index and action input index as the key of @unison_actor_ids representing the action slot, and stores the array storing the array storing the id and list of reserved action slot index of each unison invokee as that key's mapped value in @unison_actor_ids. Increases @temp_unison_inputs for each unison invokee by 1 and pushes the reserved action slot for each unison invokee into the respective list of reserved action slot indices.

5. Right after selecting a prior action slot having inputted an unison skill/item, increases @temp_unison_inputs for each unison invokee stored in the link of that action slot.

6. An actor shall never be inputable in battle if the size of the list of the reserved action slot indices >= the number of action slots.

7. prior_command and next_command of an actor shall return false if no prior and next action slots aren't reserved ones respectively. Otherwise such action slots should be selected.

8. An unison skill/item shall never be usable if the number of inputted action slots of an unison invokee >= the number of that unison invokee's action slots - @temp_unison_inputs of at least 1 unison invokee.

How and why it works:

Recall that any solution working on YEA-BattleEngine must also works on the default RMVXA battle system, and now the solution needs a script adding a new command letting players clear the currently selected action slot.

Recall the action usability change in the default battle system:

1. As all unison battlers need to be able to use the unison skill/item while only the unison invoker actually uses it, the action usability check of the unison invoker upon both inputting and executing that unison skill/item needs to check all unison battlers' usability of that unison skill/item.

Recall the 4 action input changes in the default battle system:

1. Right after an unison invoker finished inputting the unison skill/item, all other unison invokees of that unison skill/item needs to reserve an action slot for that unison skill/item.

2. Right after an action slot of an unison invoker's been replaced the previous unison skill/item with a new skill/item(or right after an previously inputted action slot with an unison skill/item's pointed to), all other unison invokees' reserved action slots for that unison skill/item need to be "freed".

3. If proceeding to the next action slot would point to a reserved one for an unison skill/item, the next action slot of that reserved one, if any(or the 1st action slot of the next inputable actor if the last action slot's reached), should be pointed to instead. Repeat until there's no more next action slots(then the Action Input Phase should be ended) or the next one isn't reserved for unison skills/items.

4. If proceeding to the prior action slot would point to a reserved one for an unison skill/item, the prior action slot of that reserved one, if any(or the last action slot of the prior inputable actor if the 1st action slot's reached), should be pointed to instead. Repeat this until there's no more prior action slots(then the party command window should be shown) or the prior one isn't reserved for unison skills/items.

Recall the 3 new constraints in YEA-BattleEngine:

1. (Minimally compromised)Previously inputted actions can only be replaced by new ones but shall never be cleared(except the new command that clears the currently selected action slot).

2. Going from the current action slot to the next one can be done without replacing the skill/item of the current one.

3. If an unison skill/item can be inputted by an actor at the start of the action input phase, players shouldn't be able to reach a situation where that actor can no longer input that unison skill/item no matter what they do in the same action input phase.

So any such algorithm must accomplish all these changes and conform to all these constraints in order to work. The below will show that they're all accomplished and conformed to by that new algorithm:

1. If at least 1 unison invokee has no ordinary and/or pretentiously empty action slot, it means that actor has none to be reserved for that unison skill/item, thus causing the unison skill/item to be not usable; If that's not the case, all the other usability requirements has already been checked by the previously modified action usability check.

2. Right after an unison invoker finished inputting the unison skill/item, the link to the reserved action slots of the previously inputted unison skill/item, if any, will be freed now. Then @unison_inputs of each current invokees will store the new reserved ones, ensuring only the correct ones will be reserved.

3. Right after an previously inputted action slot with an unison skill/item's pointed to, @temp_unison_inputs of each unison invokee's decreased by 1, causing the maximum value of the number of action slots - the number of inputted ones to be increased by 1, meaning 1 more action slot can be inputted during the unison skill/item usability check. Bear in mind that the actually reserved action slots are never freed here so the actor inputability check remains intact, what changes is the unison skill/item usability check so unison skills/items won't be locked up. That's done by pretending that the reserved action slots are already freed during the unison skill/item usability check only.

4. If proceeding to the next action slot would point to a reserved one for an unison skill/item, next_command in Game_Actor would try to find the next action slots until an ordinary empty one's found. If there's none, an inputable action slot of the next inputable actor will be selected instead.

5. If proceeding to the prior action slot would point to a reserved one for an unison skill/item, prior_command in Game_Actor would try to find the prior action slots until an ordinary empty one's found, and will return false oterwise. If there's none, an inputable action slot of the prior inputable actor will be selected instead.

6. Previously inputted actions are never cleared without using the new command that does so.

7. Using the new :dir6 command, going from the current action slot to the next one won't replace the skill/item of the current one. The old and the new unison links will be the same here as that action slot doesn't change, effectively keeping that link intact as the new one will be added right after the old one.

8. If an unison skill/item can be inputted by an actor at the start of the action input phase and it becomes locked up, players can use the new command that clears the currently selection action slot to clear 1 action slot from each unison invokee of that unison skill/item, effectively unlocking it.
Example Codes

The new command clearing the currently selected action slot:(DoubleX RMVXA Clear Addon to Yanfly Engine Ace - Ace Battle Engine)

#----------------------------------------------------------------------------| # (New)Clears the currently selected actor's currently selected action slot | #----------------------------------------------------------------------------| def clear_cur_act # Redraws the currently selected actor's part of the status window as well return unless (actor = BattleManager.actor) && actor.input actor.input.clear DoubleX_RMVXA::YEA_BattleEngine_Clear.clear_se.play @status_window.draw_item(actor.index) # end # clear_cur_act
The unison skill/item algorithm:(DoubleX RMVXA Unison Addon to Yanfly Engine Ace - Ace Battle Engine)

#------------------------------------------------------------------------------|#  * (Edit)Changes actor inputability and unison skill/item usability checks   |#------------------------------------------------------------------------------|class Game_BattlerBase  #----------------------------------------------------------------------------|  #  (Alias)Checks if at least 1 action slot isn't reserved as well            |  #----------------------------------------------------------------------------|  alias inputable_unison? inputable?  def inputable?    # Rewritten to only check the new condition against actors in battles    return false unless inputable_unison?    return true unless SceneManager.scene_is?(Scene_Battle) && @unison_inputs    @unison_inputs.size < @actions.size    #  end # inputable?  #----------------------------------------------------------------------------|  #  (Alias)Checks if unison skills/items are usable as well                   |  #----------------------------------------------------------------------------|  alias usable_unison? usable?  def usable?(item)    # Rewritten to check if all unison actors can use the unison skill/item    return usable_unison?(item) unless actor? && item &&    item.is_a?(RPG::UsableItem) && !item.unison_actor_ids.empty?    return false unless item.unison_actor_ids.include?(id)    return false unless usable_unison?(item)    return unison_skill_usable?(item) if item.is_a?(RPG::Skill)    return false unless item.is_a?(RPG::Item) && item_conditions_met?(item)    unison_item_usable?(item)    #  end # usable?  #----------------------------------------------------------------------------|  #  (New)Checks if all unison actors can use the unison skill                 |  #----------------------------------------------------------------------------|  def unison_skill_usable?(item)    # Checks if all unison actors are inputable and has the unison skill as well    battle = SceneManager.scene_is?(Scene_Battle)    (item.unison_actor_ids - [id]).each { |actor_id|      actor = $game_actors[actor_id]      return false unless actor.battle_member? && actor.inputable_unison?      return false if battle && actor.actions.select { |a| a.item }.size >=      actor.actions.size - actor.temp_unison_inputs      return false unless actor.skill_conditions_met?(item)      return false unless actor.skills.any? { |s| s == $data_skills[item.id] }    }    true    #  end # unison_skill_usable?  #----------------------------------------------------------------------------|  #  (New)Checks if all unison actors can use the unison item                  |  #----------------------------------------------------------------------------|  def unison_item_usable?(item)    # Checks if all unison actors are inputable as well    (item.unison_actor_ids - [id]).each { |actor_id|      return false unless actor.battle_member? && actor.inputable?    }    true    #  end # unison_item_usable?end # Game_BattlerBase
Code:
#------------------------------------------------------------------------------|#  * (Edit)Changes action slot inputability check                              |#------------------------------------------------------------------------------|class Game_Actor < Game_Battler  #----------------------------------------------------------------------------|  #  New public instance variable                                              |  #----------------------------------------------------------------------------|  attr_accessor :temp_unison_inputs # The number of temporarily reserved ones  attr_accessor :unison_inputs # The list of reserved action slots' indices  #----------------------------------------------------------------------------|  #  (Alias)Initializes the number and list of reserved action slots           |  #----------------------------------------------------------------------------|  alias setup_unison setup  def setup(actor_id)    setup_unison(actor_id)    # Added to initialize both the pretended and real ones as 0 and empty    @temp_unison_inputs = 0    @unison_inputs = []    #  end # setup  #----------------------------------------------------------------------------|  #  (Alias)Resets the number and list of reserved action slots                |  #----------------------------------------------------------------------------|  alias clear_actions_unison clear_actions  def clear_actions    clear_actions_unison    # Added to reset both the pretended and real ones as 0 as empty    @temp_unison_inputs = 0    @unison_inputs = []    #  end # clear_actions  #----------------------------------------------------------------------------|  #  (Alias)Prevents reserved action slots from being selected                 |  #----------------------------------------------------------------------------|  alias next_command_unison next_command  def next_command    # Rewritten to skip the next action slot if it's reserved for unison skills    last_act_input_index = @action_input_index    begin      inputable = next_command_unison    end while inputable && @unison_inputs.include?(@action_input_index)    @action_input_index = last_act_input_index unless inputable    inputable    #  end # next_command  #----------------------------------------------------------------------------|  #  (v1.00b+; Alias)Prevents reserved action slots from being selected        |  #----------------------------------------------------------------------------|  alias prior_command_unison prior_command  def prior_command    # Rewritten to skip the prior action slot if it's reserved for unison skills    last_act_input_index = @action_input_index    begin      inputable = prior_command_unison    end while inputable && @unison_inputs.include?(@action_input_index)    @action_input_index = last_act_input_index unless inputable    inputable    #  end # prior_command  #----------------------------------------------------------------------------|  #  (v1.00b+; New)Ensures the action input index won't point to reserved ones |  #----------------------------------------------------------------------------|  # i: The reserved action slot's index  # prior: Whether this actor's a prior actor to the unison invoker  def set_unison_input_index(i, prior)    # Points to the prior or next action slot according to the prior flag    return unless (@unison_inputs << i).include?(@action_input_index)    prior ? prior_command : next_command    #  end # set_unison_input_indexend # Game_Actor
Code:
#------------------------------------------------------------------------------|#  * (Edit)Reserves unison invokees' action slots for unison skills/items      |#------------------------------------------------------------------------------|class Scene_Battle < Scene_Base  #----------------------------------------------------------------------------|  #  (Alias)Initializes the unison action linkage tracker                      |  #----------------------------------------------------------------------------|  alias start_unison start  def start    start_unison    # Added to use a hash to track the unison action linkages    @unison_actor_ids = {}    #  end # start  #----------------------------------------------------------------------------|  #  (Alias)Ensures the correctness of actor inputable? and item usable? check |  #----------------------------------------------------------------------------|  alias next_command_unison next_command  def next_command    # Added to update the unison linkage of the currently selected action    if (actor = BattleManager.actor) && actor.input && actor.input.item      clear_unison_actor_ids      add_unison_actor_ids unless actor.input.item.unison_actor_ids.empty?    end    #    next_command_unison  end # next_command  #----------------------------------------------------------------------------|  #  (Alias)Ensures the correctness of unison skills/items' usability check    |  #----------------------------------------------------------------------------|  alias prior_command_unison prior_command  def prior_command    prior_command_unison    # Added to unlock the currently selected action but keep the reserved ones    return unless a = BattleManager.actor    return unless act_slots = @unison_actor_ids[[a.index, a.action_input_index]]    act_slots.each { |a_s| $game_actors[a_s[0]].temp_unison_inputs -= 1 }    #  end # prior_command  #----------------------------------------------------------------------------|  #  (Alias)Ensures supposedly valid actions will be indeed valid as well      |  #----------------------------------------------------------------------------|  alias turn_start_unison turn_start  def turn_start    # Added to reset the links of the unison action slots to the unison invokees    @unison_actor_ids = {}    $game_party.alive_members.each { |mem|      mem.temp_unison_inputs = -1      mem.unison_inputs = nil    }    #    turn_start_unison  end # turn_start  #----------------------------------------------------------------------------|  #  (Alias)Clears the currently selected action's unison linkage as well      |  #----------------------------------------------------------------------------|  alias clear_cur_act_unison clear_cur_act  def clear_cur_act    clear_cur_act_unison    # Added to free all reserved action slots of the unison skill/item if any    clear_unison_actor_ids    #  end # clear_cur_act  #----------------------------------------------------------------------------|  #  (New)Sets the link of the unison action slots to the unison invokees      |  #----------------------------------------------------------------------------|  def add_unison_actor_ids    # Reserves an inputable action slot from each unison invokee    ids = (actor = BattleManager.actor).input.item.unison_actor_ids - [actor.id]    act_slots = []    index = actor.index    ids.each { |id| act_slots << add_unison_actor_id(index, id) }    @unison_actor_ids[[index, actor.action_input_index]] = act_slots    #  end # add_unison_actor_ids  #----------------------------------------------------------------------------|  #  (v1.00b+; New)Tries not to reserve a selected inputable action slot       |  #----------------------------------------------------------------------------|  # actor_index: The index of the unison invoker of the unison skill/item  # id: The id of the unison invokee to be added  def add_unison_actor_id(actor_index, id)    # Reserves the 1st/last one if the unison invokee's prior/next actors    (a = $game_actors[id]).temp_unison_inputs += 1    index = 0    prior = a.index < actor_index    a.actions.each_with_index { |act, i|      next if act.item || (a.unison_inputs ||= []).include?(i)      prior ? (break index = i) : (next index = i)    }    a.set_unison_input_index(index, prior)    [id, index]    #  end # add_unison_actor_id  #----------------------------------------------------------------------------|  #  (New)Clears the link of the unison action slots with the unison invokees  |  #----------------------------------------------------------------------------|  def clear_unison_actor_ids    # Frees the linked reserved action slot from each unison invokee    a = BattleManager.actor    return unless act_slots = @unison_actor_ids[[a.index, a.action_input_index]]    @unison_actor_ids.delete([a.index, a.action_input_index])    act_slots.each { |a_s| $game_actors[a_s[0]].unison_inputs.delete(a_s[1]) }    #  end # clear_unison_actor_idsend # Scene_Battle

Comparisons between solution to YEA-BattleEngine and that to the default RMVXA battle system

While the solution to YEA-BattleEngine does work on the default RMVXA battle system as well, the one designed for the latter only works much, much better on the latter. That's why I decided to write another unison skill/item script for the former instead of making the existing one compatible with the former. Specifically:

- Clearing the previously inputted action slots makes sense in the latter as it'll be replaced by new ones anyway, while the same doesn't hold in the former due to the new :dir6 command which calls next_command.

- If clearing the previously inputted action slots weren't allowed in the latter, unison skills/items can become permanently locked up in the same action input phase. For instance, the 1st inputable actor has unison skills/items having the 2nd inputable actor as the unison invokee and both actors meet all the other unison skill/item requirements, but the 1st one doesn't input any unison skill, and the 2nd one inputs all the action slots. Now the 1st ones selected again and those unison skills/items can't be inputted anymore no matter what the players do, as the 2nd one has no ordinary empty action slots anymore and players can do nothing about that.

- The only way solving this is to add a new command to let players clear the currently selection action slot, which lead to a much, much worse solution than the one that clears the previously inputted ones. Now players will have to explicitly clear them to prevent from locking up unison skills/items or unlock them if they're locked up, while the one that clears the previously inputted ones will never lock up unison skills/items.

To sum up, the solution designed for the default RMVXA battle system doesn't work on YEA-BattleEngine, but the one working on YEA-BattleEngine works much, much worse than the one designed for the default RMVXA battle system on the default RMVXA battle system.
While I don't think this solution's even close to ideal, right now that's the best one I can come up with :D
 
Last edited by a moderator:

Users Who Are Viewing This Thread (Users: 0, Guests: 1)

Latest Threads

Latest Posts

Latest Profile Posts

How many parameters is 'too many'??
Yay, now back in action Happy Christmas time, coming back!






Back in action to develop the indie game that has been long overdue... Final Fallacy. A game that keeps on giving! The development never ends as the developer thinks to be the smart cookie by coming back and beginning by saying... "Oh bother, this indie game has been long overdue..." How could one resist such? No-one c
So I was playing with filters and this looked interesting...

Versus the normal look...

Kind of gives a very different feel. :LZSexcite:
To whom ever person or persons who re-did the DS/DS+ asset packs for MV (as in, they are all 48x48, and not just x2 the pixel scale) .... THANK-YOU!!!!!!!!! XwwwwX

Forum statistics

Threads
105,849
Messages
1,016,977
Members
137,563
Latest member
cexojow
Top