Extra Drops

Last Updated: 2011.12.17
Download Link
Github Link

Enemies by default only drop three items maximum in RPG Maker VX Ace. The drop rates are also limited to rates that can only be achieved through denominator values. A drop rate of say, 75% cannot be achieved. This script provides the ability to add more than just three drops and more control over the drop rates, too.

Use notetags to increase the number of drops players can get and varying rates at which items will drop. These notetags go into the enemy notebox.

<drop Ix: y%>
<drop Wx: y%>
<drop Ax: y%>

Causes enemy to drop item, weapon, or armour (marked by I, W, or A) x at a rate of y percent. Insert multiples of this tag to increase the number of drops an enemy can possibly have.

And that’s all, folks!

36 comments on “Extra Drops

  1. This is great!
    A couple questions/suggestions however:
    1: Are you going to allow for max drops?
    2: Additional drops based on variable/switch?

    3: Item tag that increases max drops from an enemy with a max amount of drops.
    -Example: Enemy has 10 possible drops (2 main drops from editor) but can only drop 1 out of those 8 extra item drops however the player has an item called goodie magnet that allows for gaining 1 additional max drop from said enemy this would give them a chance to get up to 4 out of 20 drops based on formulas.
    It would also be cool if this can be added to states/classes/heros etc.

    It would also be cool if you could add in support for weapons/armors/skills to have a chance to grant an extra item drop at the end of a battle.
    Examples:
    Accessory “Magic Goodie Bag” passive chance to give a random item at end of a battle per enemy (possibly from list).
    Weapon “Enchanted Goodie Sword” passive chance that when killing an enemy you will get an item (possibly from list) either after enemy dies during battle or at the end of battle.

    • i like this idea but would like to add a little extra could it be possible to have multiple drop pools (eg a enemy has a chance of dropping one of 3 different items from pool A, 3 out of 9 items from pool B and 2 out of 5 items from pool C)

  2. Pingback: Were are you ramiro-doo? « Ramiro + RMVXA = ♥

  3. i wonder if there is a chance to add an option.
    Like, item will only drop, when certain switch is on, if variable is larger or smaller than something.

    example:

    Item with id=90 will drop (75% chance) if switch with id=5 is on.

    <drop_cond: 2, [6

    Item with id=90 will drop(20% chance)if variable with id 6 has a value larger than 10.

    I came with that idea while playing Gothic II, when you learn how to skin animals, then some enemies will drop their skins/hides.

  4. It’s not possible to get an extra item drop from a certain kind of monsters by having the main hero have a special skill right? >..<

    • Hey! I wrote more than just that how did it end up only showing this short message.. >:c I also said, example: Getting Leather from an animal by having the the skill Skinning.

  5. How about a change so that there will be a way to generate rare drops.
    Example:
    Demon has 10% chance to drop a weapon, and from that, there is a 90% chance it’s weapon 1; 10% chance it’s weapon 2.
    Code to call it would be like (drop w:10%, 1:90%, 2:10%)…
    Then there is a 10% chance that a weapon would drop, which is mostly the common drop and occasionally the rare drop, but NEVER both drops at once.
    AS it is now, you’d need a , but there would be that once in a rare time when both would fall true and you’d get the common and rare drop both at once.

  6. It isn’t possible to get a dropchance >1%
    It would be awesome to get something like 1/10000 , just if you have like 10 epic items which COULD be dropped by a very small enemy.

  7. I got an incompability with this script : #============================================================================== # ■ Scene_SRPG #—————————————————————————— #  SRPG方式のバトル画面の処理を行うクラスです。 #============================================================================== class Scene_SRPG < Scene_Base #————————————————————————– # ● 開始処理 #————————————————————————– def start super $game_temp.in_battle = true save_map_data unit_data_new create_spriteset variable_ini character_initialize create_all_windows battle_agi_pos BattleManager.make_action_orders @subject = BattleManager.next_subject @subject.make_actions set_position create_info_viewport Graphics.update # ゲーム画面を更新 update_basic # フレーム更新 BattleManager.method_wait_for_message = method(:wait_for_message) end #————————————————————————– # ● 開始後処理 #————————————————————————– def post_start super battle_start end #————————————————————————– # ● 終了前処理 #————————————————————————– def pre_terminate super Graphics.fadeout(30) if SceneManager.scene_is?(Scene_Map) Graphics.fadeout(60) if SceneManager.scene_is?(Scene_Title) end #————————————————————————– # ● 終了処理 #————————————————————————– def terminate super dispose_spriteset @info_viewport.dispose $game_temp.in_battle = false $game_temp.player_battle_x = nil $game_temp.player_battle_y = nil $game_party.members.size.times { |i| $game_party.members[i].appear } $game_party.members.size.times { |i| $game_party.members[i].charging = false } $game_map.setup($game_temp.slg_call_position[2]) if SRPG::OTHER_BATTLE_MAP $game_temp.player_moveban = false $game_player.followers.visible = @save_followers $game_player.refresh character = get_character(-1) character.set_direction(@initial_direction) $game_player.moveto($game_temp.slg_call_position[0], $game_temp.slg_call_position[1]) $game_map.re_setup_events(@map_data) RPG::ME.stop end #————————————————————————– # ● フレーム更新 #————————————————————————– def update super if BattleManager.input_arrow? update_orders_arrow return end if BattleManager.in_operation? update_player_operation return end if BattleManager.in_turn? process_event return if @battle_break process_action end battle_judge_win_loss end #————————————————————————– # ● フレーム更新(基本) #————————————————————————– def update_basic super $game_map.update $game_player.update $game_timer.update $game_troop.update @spriteset.update update_message_open end #————————————————————————– # ● フレーム更新(ウェイト用) #————————————————————————– def update_for_wait update_basic @battler_orders_window.update end #————————————————————————– # ● ウェイト #————————————————————————– def wait(duration) duration.times {|i| update_for_wait if i = exist_unit_size $game_troop.increase_turn @fraze_count -= exist_unit_size process_event return if @battle_break end if not @subject.movable? and not @subject.current_action.forcing @subject.current_action.set_guard end @battler_orders_window.set_visible(true) # 行動が設定されているか? if @subject.current_action.forcing and not @subject.forcing_after unit_auto_play else if @subject.current_action.action_set? # 行動が設定されている場合、実行処理へ turn_start else # アクターか? エネミーか? if @subject.actor? # アクターの行動設定 if @subject.actor_inputable? and not @subject.confusion? move_range_initialize move_range_cul(@subject.x, @subject.y, @subject.move, [], 0, true, false) @status_bar_window.refresh wait_for_player_walk(@subject.x, @subject.y) @subject_ori_x = @subject.x; @subject_ori_y = @subject.y @subject_ori_d = @subject.direction BattleManager.operation_start else # 自動行動 unit_auto_play end else # エネミーの行動設定(自動行動) unit_auto_play end end end end #————————————————————————– # ● 自動ユニットの制御 #————————————————————————– def unit_auto_play @subject.make_actions_auto unless @subject.current_action.forcing @subject.current_action.set_guard if @subject.current_action.item == nil @subject.current_action.prepare confusion_unit_target if @subject.confusion? @status_bar_window.refresh($game_temp.unit_data.index(@subject), BattleManager.action_battlers) wait_for_player_walk(@subject.x, @subject.y) move_range_initialize move_range_cul(@subject.x, @subject.y, @subject.move, [], 0, true, true) set_nearest_target if @subject.current_action.can_attack_targets.empty? wait(20) target = @subject.current_action.decide_near_target decide_move_point(target) wait_for_active_battler_walk(true) reset_range_display @subject.forcing_after = true if @subject.current_action.forcing auto_can_skill?(target) BattleManager.action_battlers_update @battler_orders_window.refresh(BattleManager.action_battlers) update_basic # 更新 @subject = BattleManager.next_subject @subject.make_actions if @subject.actions.empty? start_main end #————————————————————————– # ● プレイヤー操作の更新 #————————————————————————– def update_player_operation if $game_temp.attack_arrow attack_operation else normal_move_operation end end #————————————————————————– # ● プレイヤー操作の更新 #————————————————————————– def normal_move_operation if @detail_status_window.open? update_detail_status_window return end return if @detail_status_window.openness > 0 check = check_with_characters?($game_player.x, $game_player.y) @status_bar_window.refresh(check, BattleManager.action_battlers) if Input.trigger?(Input::B) Sound.play_cancel @subject.current_action.clear start_party_command_selection return elsif Input.trigger?(Input::C) if $game_temp.move_rec.include?([$game_player.x, $game_player.y]) Sound.play_ok wait_for_active_battler_walk start_actor_command_selection return end if check != nil and check != $game_temp.unit_data.index(@subject) Sound.play_ok $game_temp.player_moveban = true @detail_status_window.refresh($game_temp.unit_data[check]) return end elsif Input.trigger?(Input::A) Sound.play_ok $game_temp.player_moveban = true @detail_status_window.refresh(@subject) return end end #————————————————————————– # ● 対象キャラ選択の更新 #————————————————————————– def attack_operation check = check_with_characters?($game_player.x, $game_player.y) @status_bar_window.refresh(check, BattleManager.action_battlers) if Input.trigger?(Input::B) Sound.play_cancel cansel_target_selection return elsif Input.trigger?(Input::C) return unless $game_temp.move_rec.include?([$game_player.x, $game_player.y]) return unless @subject.current_action.can_attack_targets.include?(check) Sound.play_ok unit = $game_temp.unit_data[check] @subject.current_action.target_index = unit.actor? ? $game_party.members.index(unit) : $game_troop.members.index(unit) end_target_selection return elsif Input.trigger?(Input::L) Sound.play_cursor @target_cursor_pos -= 1 @target_cursor_pos = @subject.current_action.can_attack_targets.size – 1 if @target_cursor_pos @subject.current_action.can_attack_targets.size – 1 unit_index = @subject.current_action.can_attack_targets[@target_cursor_pos] if unit_index != nil target = $game_temp.unit_data[unit_index] wait_for_player_walk(target.x, target.y) end return end end #————————————————————————– # ● 詳細ウィンドウ表示中 #————————————————————————– def update_detail_status_window if Input.trigger?(Input::B) or Input.trigger?(Input::C) Sound.play_cancel @detail_status_window.refresh $game_temp.player_moveban = false end end #————————————————————————– # ● アクターコマンド選択の開始 #————————————————————————– def start_actor_command_selection @skill = nil BattleManager.input_arrow_start @actor_command_window.setup(@subject) check = check_with_characters?($game_player.x, $game_player.y) @status_bar_window.refresh(check, BattleManager.action_battlers) end #————————————————————————– # ● アクターコマンド選択キャンセル #————————————————————————– def prior_command walk_battler = get_character($game_temp.unit_data.index(@subject)) walk_battler.moveto(@subject_ori_x, @subject_ori_y) @subject.set_xy(@subject_ori_x, @subject_ori_y, @subject_ori_d) @actor_command_window.close @spriteset.setup_arrow(true, nil) @spriteset.setup_arrow(false, nil) BattleManager.operation_start end #————————————————————————– # ● アクターコマンド選択の終了 #————————————————————————– def end_actor_command_selection BattleManager.input_start @status_bar_window.refresh @actor_command_window.close @spriteset.setup_arrow(true, nil) @spriteset.setup_arrow(false, nil) @spriteset.setup_scope(0) reset_range_display BattleManager.action_battlers_update @battler_orders_window.refresh(BattleManager.action_battlers) show_charge_animation if @subject.current_action.charge_time > 0 update_basic # 更新 @subject = BattleManager.next_subject @subject.make_actions if @subject.actions.empty? start_main end #————————————————————————– # ● コマンド[攻撃] #————————————————————————– def command_attack @subject.current_action.set_attack @actor_command_window.close @spriteset.setup_scope(@subject.w_scope) start_target_selection end #————————————————————————– # ● コマンド[スキル] #————————————————————————– def command_skill @skill_window.actor = @subject @skill_window.stype_id = @actor_command_window.current_ext @skill_window.refresh @skill_window.show.activate end #————————————————————————– # ● コマンド[防御] #————————————————————————– def command_guard @subject.current_action.set_guard end_actor_command_selection end #————————————————————————– # ● コマンド[アイテム] #————————————————————————– def command_item @item_window.refresh @item_window.show.activate end #————————————————————————– # ● 対象キャラ選択の開始 #————————————————————————– def start_target_selection @actor_command_window.close @skill_window.hide @item_window.hide @subject.current_action.can_attack_targets = [] search_target(@subject.x, @subject.y, true) display_attack_range @target_cursor_pos = 0 unit_index = @subject.current_action.can_attack_targets[@target_cursor_pos] if unit_index != nil target = $game_temp.unit_data[unit_index] wait_for_player_walk(target.x, target.y) end $game_temp.attack_arrow = true BattleManager.operation_start end #————————————————————————– # ● 対象キャラ選択の中止 #————————————————————————– def cansel_target_selection BattleManager.input_arrow_start $game_temp.attack_arrow = false case @actor_command_window.current_symbol when :attack @actor_command_window.open @actor_command_window.activate when :skill @actor_command_window.open @skill_window.show.activate when :item @actor_command_window.open @item_window.show.activate end @spriteset.setup_scope(0) @subject.current_action.can_attack_targets = [] temp_x = @subject.x; temp_y = @subject.y; temp_d = @subject.direction @subject.set_xy(@subject_ori_x, @subject_ori_y, @subject_ori_d) move_range_initialize move_range_cul(@subject.x, @subject.y, @subject.move, [], 0, true, false) @subject.set_xy(temp_x, temp_y, temp_d) check = $game_temp.unit_data.index(@subject) @status_bar_window.refresh(check, BattleManager.action_battlers) return end #————————————————————————– # ● 対象キャラ選択の終了 #————————————————————————– def end_target_selection $game_temp.attack_arrow = false end_actor_command_selection end #————————————————————————– # ● アクター選択の開始 #————————————————————————– def select_actor_selection @status_bar_window.refresh @actor_window.refresh @actor_window.show.activate end #————————————————————————– # ● アクター[決定] #————————————————————————– def on_actor_ok @status_bar_window.refresh($game_temp.unit_data.index(@subject), BattleManager.action_battlers) @subject.current_action.target_index = @actor_window.index @actor_window.hide @skill_window.hide @item_window.hide end_actor_command_selection end #————————————————————————– # ● アクター[キャンセル] #————————————————————————– def on_actor_cancel @status_bar_window.refresh($game_temp.unit_data.index(@subject), BattleManager.action_battlers) @actor_window.hide case @actor_command_window.current_symbol when :skill @skill_window.activate when :item @item_window.activate end end #————————————————————————– # ● スキル[決定] #————————————————————————– def on_skill_ok skill = @skill_window.item @subject.current_action.set_skill(skill.id) @subject.last_skill.object = skill if !skill.need_selection? and !skill.for_random? @skill_window.hide end_actor_command_selection elsif skill.for_dead_friend? select_actor_selection else @spriteset.setup_scope(@subject.skill_scope(skill)) start_target_selection end end #————————————————————————– # ● スキル[キャンセル] #————————————————————————– def on_skill_cancel @skill_window.hide @actor_command_window.activate end #————————————————————————– # ● アイテム[決定] #————————————————————————– def on_item_ok @item = @item_window.item @subject.current_action.set_item(@item.id) if !@item.need_selection? and !@item.for_random? @item_window.hide end_actor_command_selection elsif @item.for_dead_friend? select_actor_selection else @spriteset.setup_scope(@subject.skill_scope(@skill)) start_target_selection end $game_party.last_item.object = @item end #————————————————————————– # ● アイテム[キャンセル] #————————————————————————– def on_item_cancel @item_window.hide @actor_command_window.activate end #————————————————————————– # ● 戦闘開始 #————————————————————————– def battle_start BattleManager.battle_start process_event return if @battle_break start_party_command_selection end #————————————————————————– # ● ターン開始 #————————————————————————– def turn_start @party_command_window.close @actor_command_window.close @status_window.unselect BattleManager.turn_start @log_window.wait @log_window.clear @targets = @subject.current_action.make_targets.compact if @targets.empty? # ターゲットが居なくなっている場合 @subject.charging = false @subject.current_action.set_guard return end correct_direction(@targets[0]) if @subject.current_action.item.need_selection? or @subject.current_action.item.for_random? display_attack_range if @subject.current_action.range > 0 if @subject.current_action.item.id == @subject.attack_skill_id @spriteset.setup_scope(@subject.w_scope) else @spriteset.setup_scope(@subject.skill_scope(@subject.current_action.item)) end wait_for_player_walk(@targets[0].x, @targets[0].y) else wait_for_player_walk(@subject.x, @subject.y) end show_motion_animation end #————————————————————————– # ● ターン終了 #————————————————————————– def turn_end @subject.on_turn_end @subject.check_floor_effect_in_battle refresh_status @log_window.display_auto_affected_status(@subject) @log_window.wait_and_clear @status_bar_window.refresh @spriteset.setup_scope(0) reset_range_display BattleManager.turn_end process_event return if @battle_break if @subject.actions.empty? @fraze_count += 1 @subject.clear_actions @subject.forcing_after = false BattleManager.action_battlers_update @subject = BattleManager.next_subject @subject.make_actions if @subject.actions.empty? else @subject = BattleManager.next_subject @subject.current_action.clear @subject.forcing_after = false end @battler_orders_window.refresh(BattleManager.action_battlers) start_main end #————————————————————————– # ● 敵味方合わせた全バトルメンバーの取得 #————————————————————————– def all_battle_members $game_party.members + $game_troop.members end #————————————————————————– # ● イベントの処理 #————————————————————————– def process_event while !scene_changing? $game_troop.interpreter.update $game_troop.setup_battle_event wait_for_message wait_for_effect if $game_troop.all_dead? @battle_break = true if battle_judge_win_loss party_reset battle_agi_pos break unless $game_troop.interpreter.running? update_for_wait end end #————————————————————————– # ● 戦闘行動の処理 #————————————————————————– def process_action return if scene_changing? return turn_end unless @subject if @subject.current_action if @subject.current_action.valid? @status_bar_window.refresh execute_action else @subject.current_action.set_guard @status_bar_window.refresh execute_action end @subject.remove_current_action end return if process_action_end return turn_end end #————————————————————————– # ● 戦闘行動終了時の処理 #————————————————————————– def process_action_end @subject.on_action_end refresh_status @log_window.display_auto_affected_status(@subject) @log_window.wait_and_clear @log_window.display_current_state(@subject) @log_window.wait_and_clear return battle_judge_win_loss end #————————————————————————– # ● 戦闘行動の実行 #————————————————————————– def execute_action @subject.sprite_effect_type = :whiten use_item @log_window.wait_and_clear end #————————————————————————– # ● スキル/アイテムの使用 #————————————————————————– def use_item item = @subject.current_action.item @log_window.display_use_item(@subject, item) @subject.use_item(item) refresh_status show_animation(@targets, item.animation_id) @targets.each {|target| item.repeats.times { invoke_item(target, item) } } end #————————————————————————– # ● スキル/アイテムの発動 #————————————————————————– def invoke_item(target, item) distance = (target.x – @subject.x).abs + (target.y – @subject.y).abs if rand < target.item_cnt(@subject, item) and distance <= target.w_range invoke_counter_attack(target, item) elsif rand 0 and target.result.hit? and reflect == false refresh_status @log_window.display_action_results(target, item) end #————————————————————————– # ● 反撃の発動 #————————————————————————– def invoke_counter_attack(target, item) @log_window.display_counter(target, item) attack_skill = $data_skills[target.attack_skill_id] @subject.item_apply(target, attack_skill) @subject.damage_bar = true refresh_status @log_window.display_action_results(@subject, attack_skill) end #————————————————————————– # ● 魔法反射の発動 #————————————————————————– def invoke_magic_reflection(target, item) @log_window.display_reflection(target, item) apply_item_effects(@subject, item, true) end #————————————————————————– # ● 身代わりの適用 #————————————————————————– def apply_substitute(target, item) if check_substitute(target, item) substitute = target.friends_unit.substitute_battler if substitute && target != substitute @log_window.display_substitute(substitute, target) return substitute end end target end #————————————————————————– # ● 身代わり条件チェック #————————————————————————– def check_substitute(target, item) target.hp < target.mhp / 4 && (!item || !item.certain?) end #————————————————————————– # ● アニメーションの表示 # targets : 対象者の配列 # animation_id : アニメーション ID(-1: 通常攻撃と同じ) #————————————————————————– def show_animation(targets, animation_id) if animation_id < 0 show_attack_animation(targets) else show_normal_animation(targets, animation_id) end @log_window.wait wait_for_animation end #————————————————————————– # ● 攻撃アニメーションの表示 # targets : 対象者の配列 # アクターの場合は二刀流を考慮(左手武器は反転して表示)。 # 敵キャラの場合は [敵の通常攻撃] 効果音を演奏して一瞬待つ。 #————————————————————————– def show_attack_animation(targets) if @subject.actor? show_normal_animation(targets, @subject.atk_animation_id1, false) show_normal_animation(targets, @subject.atk_animation_id2, true) else show_normal_animation(targets, @subject.w_atk_anime_id, false) end end #————————————————————————– # ● 通常アニメーションの表示 # targets : 対象者の配列 # animation_id : アニメーション ID # mirror : 左右反転 #————————————————————————– def show_normal_animation(targets, animation_id, mirror = false) animation = $data_animations[animation_id] if animation targets.each do |target| target.animation_id = animation_id target.animation_mirror = mirror abs_wait_short unless animation.to_screen? end abs_wait_short if animation.to_screen? end end #————————————————————————– # ● プレイヤーの移動が終わるまでウェイト #————————————————————————– def wait_for_player_walk(x, y) while $game_player.x != x or $game_player.y != y $game_player.walkto(x, y) update_basic end abs_wait(5) end #————————————————————————– # ● アクティブバトラーの移動が終わるまでウェイト #————————————————————————– def wait_for_active_battler_walk(auto = false) unless auto route = $game_temp.move_table[$game_player.x] [$game_player.y][1] else route = $game_temp.move_table[@subject.move_pos_x] [@subject.move_pos_y][1] end route.push(0) # 終了の合図を追加 walk_battler = get_character($game_temp.unit_data.index(@subject)) i = 0 loop do update_basic next if walk_battler.moving? dir = route[i] walk_battler.active_battler_walkto(dir) break if dir == 0 i += 1 end route.pop @subject.set_xy(walk_battler.x, walk_battler.y, walk_battler.direction) end #————————————————————————– # ● 存在するユニットの人数を返す #————————————————————————– def exist_unit_size return $game_party.alive_members.size + $game_troop.alive_members.size end #————————————————————————– # ● 変数の初期化 #————————————————————————– def variable_ini @hp0_actor_target = nil # HP0のユニット @fraze_count = exist_unit_size # フレーズカウント(ターンのカウントに使う) @subject = nil # 行動しているユニット $game_temp.attack_arrow = false # 攻撃中か判定するフラグ $game_temp.move_rec = [] # 範囲表示先の保存配列 $game_temp.player_moveban = false # プレイヤーの移動許可フラグ @save_party_members = $game_party.members.clone # パーティーメンバーを保存 @battle_break = false # 戦闘を強制終了するフラグ end #————————————————————————– # ● ユニットデータの作成 #————————————————————————– def unit_data_new $game_temp.unit_data = [] $game_temp.unit_data[0] = nil # イベントIDに合わせるため、0をnilにする for i in 0 .. 3 if $game_party.members[i] != nil $game_temp.unit_data.push($game_party.members[i]) else $game_temp.unit_data.push(nil) end end for i in 0 .. 7 if $game_troop.members[i] != nil $game_temp.unit_data.push($game_troop.members[i]) else $game_temp.unit_data.push(nil) end end end #————————————————————————– # ● 戦闘終了時のために必要なマップデータを保存 #————————————————————————– def save_map_data @map_data = $game_map.prebattle_map_data $game_temp.slg_call_position = [$game_player.x, $game_player.y, $game_map.map_id] $game_map.setup($game_variables[SRPG::BATTLEMAP_VARIABLE]) if SRPG::OTHER_BATTLE_MAP $game_map.battle_setup_events $game_map.set_panorama(@map_data) $game_map.refresh end #————————————————————————– # ● プレイヤーとキャラクターを初期化 #————————————————————————– def character_initialize character = get_character(-1) if SRPG::OTHER_BATTLE_MAP $game_temp.player_battle_x = $game_map.width / 2 $game_temp.player_battle_y = $game_map.height / 2 if SRPG::OTHER_B_M_DIRECTION character.set_direction(4) else character.set_direction(8) end else if $game_temp.player_battle_x == nil and $game_temp.player_battle_y == nil $game_temp.player_battle_x = $game_player.x $game_temp.player_battle_y = $game_player.y end end $game_player.moveto($game_temp.player_battle_x, $game_temp.player_battle_y) $game_temp.player_moveban = true @save_followers = $game_player.followers.visible $game_player.followers.visible = false @initial_direction = character.direction $game_player.refresh # イベントの位置を初期化 for i in 1 .. 12 character = get_character(i) character.moveto(0, 0) unit = $game_temp.unit_data[i] unit.set_xy(0, 0, character.direction) if unit != nil end end #————————————————————————– # ● ユニットの位置を設定 #————————————————————————– def set_position # 前後のスペースを確認 # 主人公の位置と向きを取得し、基点として設定 character = get_character(-1) @player_base_x = character.x @player_base_y = character.y @player_direction = character.direction # 周囲にスペースがあるか確認する chack = chack_space(@player_base_x, @player_base_y) # マップ上のアクターの位置を設定 set_position_actor # マップ上のエネミーの位置を設定 set_position_enemy end #————————————————————————– # ● 通行可能判定 # d : 方向(2,4,6,8) #————————————————————————– def passable?(x, y, d, character_check = true) x2 = $game_map.round_x_with_direction(x, d) y2 = $game_map.round_y_with_direction(y, d) return false unless $game_map.valid?(x2, y2) return false unless $game_map.in_map?(x2, y2) return true if $game_temp.attack_arrow return false unless map_passable?(x, y, d) return false unless map_passable?(x2, y2, reverse_dir(d)) return false if collide_with_characters?(x2, y2) and character_check return true end #————————————————————————– # ● マップ通行可能判定 # d : 方向(2,4,6,8) #————————————————————————– def map_passable?(x, y, d) $game_map.passable?(x, y, d) end #————————————————————————– # ● イベントとの衝突判定 #————————————————————————– def collide_with_characters?(x, y) for unit in $game_temp.unit_data # イベントの座標と一致 # イベントと重なったら弾く if unit != nil return true if (unit.x == x and unit.y == y) and unit.alive? and not unit.appear_flag end end return false end #————————————————————————– # ● イベントとの衝突判定 #————————————————————————– def check_with_characters?(x, y) for unit in $game_temp.unit_data # イベントの座標と一致 # イベントと重なったらIDを返す if unit != nil return $game_temp.unit_data.index(unit) if (unit.x == x and unit.y == y) and unit.alive? end end return nil end #————————————————————————– # ● ベクトルデータをもとに移動演算する #————————————————————————– def vector_cal(vector, x, y) for i in vector case i when 1 # 座標認識のための特殊コード check_x = x; check_y = y when 2 y += 1 if passable?(x, y, i) when 8 y -= 1 if passable?(x, y, i) when 4 x -= 1 if passable?(x, y, i) when 6 x += 1 if passable?(x, y, i) end end return [x, y, check_x, check_y] end #————————————————————————– # ● ベクトルデータを主人公の向きに合わせて修正する(下向きを基準とする) #————————————————————————– def vector_change(vector, direction) new_vector = [] case direction when 2 new_vector += vector when 4 for i in vector new_vector.push(1) if i == 1 new_vector.push(4) if i == 2 new_vector.push(8) if i == 4 new_vector.push(2) if i == 6 new_vector.push(6) if i == 8 end when 6 for i in vector new_vector.push(1) if i == 1 new_vector.push(6) if i == 2 new_vector.push(2) if i == 4 new_vector.push(8) if i == 6 new_vector.push(4) if i == 8 end when 8 for i in vector new_vector.push(1) if i == 1 new_vector.push(8) if i == 2 new_vector.push(6) if i == 4 new_vector.push(4) if i == 6 new_vector.push(2) if i == 8 end end return new_vector end #————————————————————————– # ● プレイヤーの向きを逆転する #————————————————————————– def reverse_dir(direction) player_d = 8 if direction == 2 player_d = 6 if direction == 4 player_d = 4 if direction == 6 player_d = 2 if direction == 8 return player_d end #————————————————————————– # ● スタート地点に誰もいないか確認 #————————————————————————– def check_start(x, y, direction) unit_check = collide_with_characters?(x, y) unless unit_check return [x, y] else # 向きを設定する(できるだけ相手から遠ざかる) case direction when 2 front = 2; left = 6; right = 4; back = 8 when 4 front = 4; left = 2; right = 8; back = 6 when 6 front = 6; left = 8; right = 2; back = 4 when 8 front = 8; left = 4; right = 6; back = 2 end # 4方向へ探索 seek_orders = [back, left, right, front] dir = check_4_dir(x, y, seek_orders, front, left, right, back) return dir end end #————————————————————————– # ● 4方向探索 #————————————————————————– def check_4_dir(x, y, seek_orders, front, left, right, back, dir = nil) for direction in seek_orders # 要求通りの順番に4方向探索 new_x = x + (direction == 6 ? 1 : direction == 4 ? -1 : 0) new_y = y + (direction == 2 ? 1 : direction == 8 ? -1 : 0) # 後ろ方向にアンカーを伸ばす if direction == back and dir == nil # 同じ方向には、調べる必要なし if passable?(x, y, direction, false) if collide_with_characters?(new_x, new_y) dir = check_4_dir(new_x, new_y, [back, left, right, front], front, left, right, back) else return [new_x, new_y] end end end # 右方向にアンカーを伸ばす if direction == right and dir == nil # 同じ方向には、調べる必要なし if passable?(x, y, direction, false) if collide_with_characters?(new_x, new_y) dir = check_4_dir(new_x, new_y, [right, back, front, left], front, left, right, back) else return [new_x, new_y] end end end # 左方向にアンカーを伸ばす if direction == left and dir == nil # 同じ方向には、調べる必要なし if passable?(x, y, direction, false) if collide_with_characters?(new_x, new_y) dir = check_4_dir(new_x, new_y, [left, back, front, right], front, left, right, back) else return [new_x, new_y] end end end # 前方向にアンカーを伸ばす if direction == front and dir == nil # 同じ方向には、調べる必要なし if passable?(x, y, direction, false) if collide_with_characters?(new_x, new_y) dir = check_4_dir(new_x, new_y, [front, right, left, back], front, left, right, back) else return [new_x, new_y] end end end end return dir end #————————————————————————– # ● 上下にスペースがあるか確認する #————————————————————————– def chack_space(x, y) # 主人公の前方が詰まっている時の為に補正 vector = [2, 2, 2, 1, 8, 8, 8] # ベクトルデータを主人公の向きに合わせて修正 vector = vector_change(vector, @player_direction) # 演算開始 x_y = vector_cal(vector, x, y) # 座標確認 check_x = x_y[2] – x_y[0]; check_y = x_y[3] – x_y[1] check_x = check_x.abs; check_y = check_y.abs if (check_x < 3 and check_y == 0) or (check_x == 0 and check_y < 3) # 前後が詰まっていると判断 # 主人公の向きを90度回転する i = rand(1) case @player_direction when 2 @player_direction = (i == 0 ? 4 : 6) when 4 @player_direction = (i == 0 ? 8 : 2) when 6 @player_direction = (i == 0 ? 2 : 8) when 8 @player_direction = (i == 0 ? 6 : 4) end end return end #————————————————————————– # ● アクターの位置を設定する #————————————————————————– def set_position_actor # 各ポジションのアクターの数を計算 position_0 = []; position_1 = []; position_2 = [] for i in 0 … $game_party.members.size actor = $game_party.members[i] case actor.position when 0 position_0.push(i) when 1 position_1.push(i) when 2 position_2.push(i) end end # 各キャラクターごとにベクトルを計算して移動 # 奥から詰めるために、後列orパーティーの後ろにいるキャラを先に計算する position_actor = [] position_actor = position_actor + position_2.reverse + position_1.reverse + position_0.reverse pos0_num = 0; pos1_num = 0; pos2_num = 0 for id in position_actor vector = [] # ポジションと各ポジションにいるアクター数から立ち位置を計算 actor = $game_party.members[id] case actor.position when 0 case position_0.size when 2 vector.push(4) if pos0_num == 0 vector.push(6) if pos0_num == 1 when 3 vector.push(6, 6) if pos0_num == 0 vector.push(4, 4) if pos0_num == 1 when 4 vector.push(4, 4, 4) if pos0_num == 0 vector.push(6, 6, 6) if pos0_num == 1 vector.push(4) if pos0_num == 2 vector.push(6) if pos0_num == 3 end pos0_num += 1 when 1 vector.push(8) case position_1.size when 2 vector.push(4) if pos1_num == 0 vector.push(6) if pos1_num == 1 when 3 vector.push(6, 6) if pos1_num == 0 vector.push(4, 4) if pos1_num == 1 when 4 vector.push(4, 4, 4) if pos1_num == 0 vector.push(6, 6, 6) if pos1_num == 1 vector.push(4) if pos1_num == 2 vector.push(6) if pos1_num == 3 end pos1_num += 1 when 2 vector.push(8, 8) case position_2.size when 2 vector.push(4) if pos2_num == 0 vector.push(6) if pos2_num == 1 when 3 vector.push(6, 6) if pos2_num == 0 vector.push(4, 4) if pos2_num == 1 when 4 vector.push(4, 4, 4) if pos2_num == 0 vector.push(6, 6, 6) if pos2_num == 1 vector.push(4) if pos2_num == 2 vector.push(6) if pos2_num == 3 end pos2_num += 1 end # 基点まで移動 vector.push(8, 8) # ベクトルデータを主人公の向きに合わせて修正 vector = vector_change(vector, @player_direction) # 主人公の位置を基準に 重なっていないか確認 start_xy = check_start(@player_base_x, @player_base_y, @player_direction) # 演算開始 x_y = vector_cal(vector, start_xy[0], start_xy[1]) # イベントを取得し、位置を設定 character = get_character(id + 1) character.moveto(x_y[0], x_y[1]) # イベントの位置をユニットに記録 unit = $game_temp.unit_data[id + 1] unit.set_xy(x_y[0], x_y[1], character.direction) character.set_direction(@player_direction) end end #————————————————————————– # ● エネミーの位置を設定する #————————————————————————– def set_position_enemy # 主人公の向きを逆転する(主人公に正対するため) player_d = reverse_dir(@player_direction) ## 各キャラクターごとにベクトルを計算して移動する # 各キャラの座標を設定(ランダムセットもここで行う) for enemy in $game_troop.members.reverse x = enemy.screen_x; y = enemy.screen_y # ランダムセット if x == 0 or x == 544 or y == 16 or y == 296 # X座標生成 x += rand(544) – 272 x = (x 544 ? x – 272 : x) y += rand(296) – 148 y = (y 296 ? y – 148 : y) end # screen_xyをマップ上の座標に変換して保存 enemy.slg_x = x / 32; enemy.slg_y = y / 32 end # Y座標の小さいもの順にソートする(奥から詰めるため) new_enemy = [] $game_troop.members.each {|enemy| new_enemy.push(enemy) } new_enemy.sort! do |a,b| a.slg_y – b.slg_y end # トループのユニット配置情報をマップ上の座標情報に変換 for enemy in new_enemy vector = [] x = enemy.slg_x; y = enemy.slg_y # プレイヤーの位置を(8,6)と置いて、x,yの差からベクトルを出す temp = (11 – y) / 2 while temp != 0 temp -= 1 vector.push(8) end temp = (x – 8) / 2 if temp 0 while temp != 0 temp -= 1 vector.push(6) end end # ベクトルデータを主人公の向きに合わせて修正 vector = vector_change(vector, player_d) # 主人公の位置を基準に 重なっていないか確認 start_xy = check_start(@player_base_x, @player_base_y, @player_direction) # 演算開始 x_y = vector_cal(vector, start_xy[0], start_xy[1]) # イベントを取得し、位置を設定 character = get_character(enemy.index + 5) character.moveto(x_y[0], x_y[1]) # イベントの位置をユニットに記録 unit = $game_temp.unit_data[enemy.index + 5] unit.set_xy(x_y[0], x_y[1], character.direction) character.set_direction(player_d) end end #————————————————————————– # ● 移動範囲初期化 #————————————————————————– def move_range_initialize left_x = $game_temp.player_battle_x – SRPG::BattleField_X / 2 right_x = $game_temp.player_battle_x + SRPG::BattleField_X / 2 up_y = $game_temp.player_battle_y – SRPG::BattleField_Y / 2 down_y = $game_temp.player_battle_y + SRPG::BattleField_Y / 2 left_x = left_x > 0 ? left_x : 0 right_x = right_x 0 ? up_y : 0 down_y = down_y < $game_map.height ? down_y : $game_map.height – 1 $game_temp.move_table = [] for i in left_x .. right_x vartical = [] for j in up_y .. down_y vartical[j] = [-1, []] end $game_temp.move_table[i] = vartical end $game_temp.move_rec = [] update_basic # 更新 # アクティブバトラーの直下は常に歩ける $game_temp.move_table[@subject.x] [@subject.y] = [@subject.move, [0]] $game_temp.move_rec.push([@subject.x, @subject.y]) end #————————————————————————– # ● 移動範囲演算 #————————————————————————– def move_range_cul(x, y, move, route, anti_dir, chara_check, targetting = false) # 自動操作の時、攻撃可能な相手をリストに入れておく search_target(x, y) if targetting # move=0だと、その先は必ず-1になるので演算不要 return if move <= 0 # 4方向演算 if anti_dir != 6 # 右方向へ計算 if passable?(x, y, 6, chara_check) # 通行可能か判定 if $game_temp.move_table[x+1] [y][0] < move – 1 # 移動先のmoveが現在値より低い場合 $game_temp.move_table[x+1] [y] = [move-1, route + [6]] $game_temp.move_rec.push([x+1, y]) move_range_cul(x+1, y, move-1, route + [6], 4, chara_check, targetting) end end end if anti_dir != 4 # 左方向へ計算 if passable?(x, y, 4, chara_check) # 通行可能か判定 if $game_temp.move_table[x-1] [y][0] < move – 1 # 移動先のmoveが現在値より低い場合 $game_temp.move_table[x-1] [y] = [move-1, route + [4]] $game_temp.move_rec.push([x-1, y]) move_range_cul(x-1, y, move-1, route + [4], 6, chara_check, targetting) end end end if anti_dir != 8 # 上方向へ計算 if passable?(x, y, 8, chara_check) # 通行可能か判定 if $game_temp.move_table[x] [y-1][0] < move – 1 # 移動先のmoveが現在値より低い場合 $game_temp.move_table[x] [y-1] = [move-1, route + [8]] $game_temp.move_rec.push([x, y-1]) move_range_cul(x, y-1, move-1, route + [8], 2, chara_check, targetting) end end end if anti_dir != 2 # 下方向へ計算 if passable?(x, y, 2, chara_check) # 通行可能か判定 if $game_temp.move_table[x] [y+1][0] 0 dis = (x – battler.x).abs + (y – battler.y).abs if dis == @subject.current_action.range and flag == false t_index = $game_temp.unit_data.index(battler) @subject.current_action.can_attack_targets.push(t_index) end if dis <= @subject.current_action.range and flag == true t_index = $game_temp.unit_data.index(battler) @subject.current_action.can_attack_targets.push(t_index) end else t_index = $game_temp.unit_data.index(battler) @subject.current_action.can_attack_targets.push(t_index) end end end #————————————————————————– # ● 最短距離にいる相手を入力(最適距離が居ないとき) #————————————————————————– def set_nearest_target if @subject.current_action.item.for_friend? targets = @subject.current_action.friends_unit else targets = @subject.current_action.opponents_unit end nearest = 99999 for battler in targets.members next if battler == nil or not battler.alive? dis = (@subject.x – battler.x).abs + (@subject.y – battler.y).abs if dis == nearest t_index = $game_temp.unit_data.index(battler) @subject.current_action.can_attack_targets.push(t_index) end if dis < nearest nearest = dis @subject.current_action.can_attack_targets = [] t_index = $game_temp.unit_data.index(battler) @subject.current_action.can_attack_targets.push(t_index) end end end #————————————————————————– # ● 移動先を決定する #————————————————————————– def decide_move_point(battler) if @subject.current_action.wait? @subject.move_pos_x = @subject.x @subject.move_pos_y = @subject.y return end if @subject.current_action.item.need_selection? or @subject.current_action.item.for_random? if @subject.current_action.range == 0 range = rand(SRPG::RANDOM_RANGE_R) + SRPG::RANDOM_RANGE_M else range = @subject.current_action.range end else @subject.move_pos_x = @subject.x @subject.move_pos_y = @subject.y return end nearest = 99999 for x_y in $game_temp.move_rec dis = (x_y[0] – battler.x).abs + (x_y[1] – battler.y).abs if dis == range @subject.move_pos_x = x_y[0] @subject.move_pos_y = x_y[1] return end if dis < nearest nearest = dis @subject.move_pos_x = x_y[0] @subject.move_pos_y = x_y[1] end end end #————————————————————————– # ● 戦闘の素早さ基準点の更新 #————————————————————————– def battle_agi_pos max_agi = 0 for unit in $game_temp.unit_data max_agi = unit.agi if unit != nil and max_agi 0 move_range_cul(@subject.x, @subject.y, @subject.current_action.range, [], 0, false, false) else $game_temp.move_rec = [] for id in @subject.current_action.can_attack_targets character = $game_temp.unit_data[id] $game_temp.move_rec.push([character.x, character.y]) end end end #————————————————————————– # ● 攻撃対象の方向を向く #————————————————————————– def correct_direction(target) character = get_character($game_temp.unit_data.index(@subject)) check_x = target.x – @subject.x; check_x *= -1 if check_x < 0 check_y = target.y – @subject.y; check_y *= -1 if check_y @subject.x and target.y check_y chara_dir = 8 if check_x <= check_y elsif target.x < @subject.x and target.y check_y chara_dir = 8 if check_x <= check_y elsif target.x @subject.y # 第3象限 chara_dir = 4 if check_x > check_y chara_dir = 2 if check_x @subject.x and target.y > @subject.y # 第4象限 chara_dir = 6 if check_x > check_y chara_dir = 2 if check_x @subject.y # 下 chara_dir = 2 elsif target.x @subject.x and target.y == @subject.y # 右 chara_dir = 6 elsif target.x == @subject.x and target.y 0 @subject.set_xy(character.x, character.y, character.direction) end #————————————————————————– # ● アロースプライトの変更 #————————————————————————– def update_orders_arrow case @actor_command_window.current_symbol when :attack skill = $data_skills[@subject.attack_skill_id] when :skill skill = @skill_window.visible? ? @skill_window.item : nil when :item skill = @item_window.visible? ? @item_window.item : nil when :guard skill = $data_skills[@subject.guard_skill_id] end if skill == nil @skill = nil @spriteset.setup_arrow(true, nil) @spriteset.setup_arrow(false, nil) return end return if @skill == skill @skill = skill @subject.current_action.charge_time = @subject.skill_charge(skill) @subject.current_action.add_wait = @subject.skill_add_wait(skill) @spriteset.setup_arrow(true, BattleManager.arrow_wait_cul(true)) @spriteset.setup_arrow(false, BattleManager.arrow_wait_cul(false)) end #————————————————————————– # ● 詠唱時のアニメーション表示 #————————————————————————– def show_charge_animation return if @subject.skill_charge(@subject.current_action.item) == 0 if SRPG::CHARGE_ANIMATION != 0 show_normal_animation([@subject], SRPG::CHARGE_ANIMATION) wait_for_animation else Sound.play_use_skill wait(20) end @subject.charging = true end #————————————————————————– # ● 発動時のアニメーション表示 #————————————————————————– def show_motion_animation return if @subject.skill_charge(@subject.current_action.item) == 0 if SRPG::MOTION_ANIMATION != 0 show_normal_animation([@subject], SRPG::MOTION_ANIMATION) wait_for_animation else Sound.play_use_skill wait(20) end @subject.charging = false end #————————————————————————– # ● 射程があるスキルが可能か判定 #————————————————————————– def auto_can_skill?(target) if not @subject.current_action.item.need_selection? and not @subject.current_action.item.for_random? show_charge_animation return end if @subject.current_action.item.for_dead_friend? show_charge_animation return end if @subject.current_action.range > 0 dis = (target.x – @subject.x).abs + (target.y – @subject.y).abs if dis > @subject.current_action.range @subject.current_action.set_guard return end end @spriteset.setup_scope(@subject.skill_scope(@subject.current_action.item)) wait_for_player_walk(target.x, target.y) show_charge_animation @spriteset.setup_scope(0) end #————————————————————————– # ● ユニットの座標を再設定(戦闘不能からの復帰時) #————————————————————————– def reset_unit_xy(target) x_y = check_start(target.x, target.y, @initial_direction) character = get_character($game_temp.unit_data.index(target)) character.moveto(x_y[0], x_y[1]) target.set_xy(x_y[0], x_y[1], character.direction) end #————————————————————————– # ● デスペナルティ # 復活・出現したユニットが即行動しないために必要 #————————————————————————– def death_pena(battler) speed = ($game_temp.max_agi – battler.agi) / 2 speed *= SRPG::BATTLE_SPEED BattleManager.battler_action_speed_plus(battler, speed) end #————————————————————————– # ● ユニットの入れ替え #————————————————————————– def party_reset @battler_orders_window.refresh(BattleManager.action_battlers) for unit in $game_temp.unit_data.compact unit_appear(unit) if unit.appear_flag end return if @save_party_members == $game_party.members unit_data_new for actor in $game_party.members if not @save_party_members.include?(actor) death_pena(actor) vector = [8, 8, 8] vector = vector_change(vector, @player_direction) start_xy = check_start(@player_base_x, @player_base_y, @player_direction) x_y = vector_cal(vector, start_xy[0], start_xy[1]) character = get_character($game_party.members.index(actor) + 1) character.moveto(x_y[0], x_y[1]) actor.set_xy(x_y[0], x_y[1], character.direction) character.set_direction(@player_direction) @spriteset.character_sprites[character.id – 1].set_battler(actor) end end @battler_orders_window.refresh(BattleManager.action_battlers) @save_party_members = $game_party.members.clone end #————————————————————————– # ● ユニットの出現処理 #————————————————————————– def unit_appear(unit) death_pena(unit) start_xy = check_start(unit.x, unit.y, reverse_dir(@player_direction)) character = get_character($game_temp.unit_data.index(unit)) character.moveto(start_xy[0], start_xy[1]) unit.set_xy(start_xy[0], start_xy[1], reverse_dir(@player_direction)) character.set_direction(reverse_dir(@player_direction)) unit.appear_flag = false end #————————————————————————– # ● 戦闘終了の処理 #————————————————————————– def battle_judge_win_loss return unless BattleManager.pre_judge_win_loss @status_bar_window.refresh @spriteset.setup_scope(0) reset_range_display @battler_orders_window.refresh(BattleManager.action_battlers) return BattleManager.judge_win_loss end #————————————————————————– # ● 混乱時にどちらの陣営を攻撃するか決める #————————————————————————– def confusion_unit_target case @subject.confusion_level when 1 @subject.current_action.confusion_target_unit = 0 when 2 if rand(2) == 0 @subject.current_action.confusion_target_unit = 0 else @subject.current_action.confusion_target_unit = 1 end else @subject.current_action.confusion_target_unit = 1 end end #————————————————————————– # ● キャラクターの取得 # param : -1 ならプレイヤー、0 ならこのイベント、それ以外はイベント ID #————————————————————————– def get_character(param) case param when -1 # プレイヤー return $game_player when 0 # このイベント events = $game_map.events return events == nil ? nil : events[@event_id] else # 特定のイベント events = $game_map.events return events == nil ? nil : events[param] end end end
  8. Pingback: My Introduction to RPG Maker VX ACE | RPG Maker VX ACE Information

    • Ok, I tested and it doesnt stack with drop item double (party ability)
      it would be nice if both works together (% in notetag *2 by the party skill)
      anyway, this saved my life, thx a lot!

  9. Yanfly, could you help me please?
    I want to make the Ace’s default item drop double work with your
    script but every time i try it the only thing i get is doubling every drop chance,
    even when i don’t have the drop doubler active.
    Thank you.

    • The dropbox is down. Ihttps://yanflychannel.wordpress.com/2014/03/30/script-links-temporarily-down/ It’s available on the github.

    • Oh wow, nevermind. I read that completely wrong. >.<; 1 in 4 is 25%. Ignore me, it's been a long night. Hopefully you at least got a chuckle out of this.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s