diff --git a/src/game_actor.cpp b/src/game_actor.cpp index 5f4ee62932..d9483da399 100644 --- a/src/game_actor.cpp +++ b/src/game_actor.cpp @@ -84,7 +84,7 @@ int Game_Actor::GetId() const { return actor_id; } -bool Game_Actor::UseItem(int item_id) { +bool Game_Actor::UseItem(int item_id, const Game_Battler* source) { const RPG::Item* item = ReaderUtil::GetElement(Data::items, item_id); if (!item) { Output::Warning("UseItem: Can't use invalid item %d", item_id); @@ -110,7 +110,7 @@ bool Game_Actor::UseItem(int item_id) { return true; } - return Game_Battler::UseItem(item_id); + return Game_Battler::UseItem(item_id, source); } bool Game_Actor::IsItemUsable(int item_id) const { diff --git a/src/game_actor.h b/src/game_actor.h index 3695af3c43..e2dd5929a3 100644 --- a/src/game_actor.h +++ b/src/game_actor.h @@ -73,7 +73,7 @@ class Game_Actor : public Game_Battler { * @param item_id ID if item to use * @return true if item affected anything */ - bool UseItem(int item_id) override; + bool UseItem(int item_id, const Game_Battler* source) override; /** * Checks if the actor is permitted to use the item at all. diff --git a/src/game_battler.cpp b/src/game_battler.cpp index 9aae16625f..a3a5473ea2 100644 --- a/src/game_battler.cpp +++ b/src/game_battler.cpp @@ -233,7 +233,7 @@ bool Game_Battler::IsSkillUsable(int skill_id) const { return true; } -bool Game_Battler::UseItem(int item_id) { +bool Game_Battler::UseItem(int item_id, const Game_Battler* source) { const RPG::Item* item = ReaderUtil::GetElement(Data::items, item_id); if (!item) { Output::Warning("UseItem: Can't use item with invalid ID %d", item_id); @@ -282,7 +282,7 @@ bool Game_Battler::UseItem(int item_id) { return true; } - bool do_skill = RPG::Item::Type_special + bool do_skill = (item->type == RPG::Item::Type_special) || (item->use_skill && ( item->type == RPG::Item::Type_weapon || item->type == RPG::Item::Type_shield @@ -294,19 +294,17 @@ bool Game_Battler::UseItem(int item_id) { if (do_skill) { auto* skill = ReaderUtil::GetElement(Data::skills, item->skill_id); - if (skill != nullptr) { - Game_Battler* source = this; - if (skill->scope != RPG::Skill::Scope_self) { - source = Main_Data::game_party->GetHighestLeveledActorWhoCanAct(); - } - UseSkill(item->skill_id, source); + if (skill == nullptr) { + Output::Warning("UseItem: Can't use item %d skill with invalid ID %d", item->ID, item->skill_id); + return false; } + UseSkill(item->skill_id, source); } return false; } -bool Game_Battler::UseSkill(int skill_id, Game_Battler* source) { +bool Game_Battler::UseSkill(int skill_id, const Game_Battler* source) { const RPG::Skill* skill = ReaderUtil::GetElement(Data::skills, skill_id); if (!skill) { Output::Warning("UseSkill: Can't use skill with invalid ID %d", skill_id); diff --git a/src/game_battler.h b/src/game_battler.h index 5b9cca4a19..c37271e5e1 100644 --- a/src/game_battler.h +++ b/src/game_battler.h @@ -352,7 +352,7 @@ class Game_Battler { * @param item_id ID if item to use * @return true if item affected anything */ - virtual bool UseItem(int item_id); + virtual bool UseItem(int item_id, const Game_Battler* source); /** * Applies the effects of a skill. @@ -364,7 +364,7 @@ class Game_Battler { * @param source battler who threw the skill * @return true if skill affected anything */ - virtual bool UseSkill(int skill_id, Game_Battler* source); + virtual bool UseSkill(int skill_id, const Game_Battler* source); /** * Calculates the Skill costs including all modifiers. diff --git a/src/game_party.cpp b/src/game_party.cpp index 55bbd984ce..effe066f1a 100644 --- a/src/game_party.cpp +++ b/src/game_party.cpp @@ -218,34 +218,36 @@ bool Game_Party::IsItemUsable(int item_id, const Game_Actor* target) const { return false; } - if (item_id > 0 && item_id <= (int)Data::items.size() && data().party.size() > 0) { + if (data().party.size() == 0) { + return false; + } + + switch (item->type) { + case RPG::Item::Type_weapon: + case RPG::Item::Type_shield: + case RPG::Item::Type_armor: + case RPG::Item::Type_helmet: + case RPG::Item::Type_accessory: + return item->use_skill && IsSkillUsable(item->skill_id, nullptr, true); + case RPG::Item::Type_special: + return IsSkillUsable(item->skill_id, nullptr, true); + } + + if (Game_Temp::battle_running) { switch (item->type) { - case RPG::Item::Type_weapon: - case RPG::Item::Type_shield: - case RPG::Item::Type_armor: - case RPG::Item::Type_helmet: - case RPG::Item::Type_accessory: - return item->use_skill && IsSkillUsable(item->skill_id, nullptr, true); - case RPG::Item::Type_special: - return IsSkillUsable(item->skill_id, nullptr, true); + case RPG::Item::Type_medicine: + return !item->occasion_field1; + case RPG::Item::Type_switch: + return item->occasion_battle; } - - if (Game_Temp::battle_running) { - switch (item->type) { - case RPG::Item::Type_medicine: - return !item->occasion_field1; - case RPG::Item::Type_switch: - return item->occasion_battle; - } - } else { - switch (item->type) { - case RPG::Item::Type_medicine: - case RPG::Item::Type_material: - case RPG::Item::Type_book: - return true; - case RPG::Item::Type_switch: - return item->occasion_field2; - } + } else { + switch (item->type) { + case RPG::Item::Type_medicine: + case RPG::Item::Type_material: + case RPG::Item::Type_book: + return true; + case RPG::Item::Type_switch: + return item->occasion_field2; } } @@ -255,16 +257,49 @@ bool Game_Party::IsItemUsable(int item_id, const Game_Actor* target) const { bool Game_Party::UseItem(int item_id, Game_Actor* target) { bool was_used = false; + auto* item = ReaderUtil::GetElement(Data::items, item_id); + if (!item) { + Output::Warning("UseItem: Can't use item with invalid ID %d", item_id); + return false; + } + + bool do_skill = (item->type == RPG::Item::Type_special) + || (item->use_skill && ( + item->type == RPG::Item::Type_weapon + || item->type == RPG::Item::Type_shield + || item->type == RPG::Item::Type_armor + || item->type == RPG::Item::Type_helmet + || item->type == RPG::Item::Type_accessory + ) + ); + + const RPG::Skill* skill = nullptr; + if (do_skill) { + skill = ReaderUtil::GetElement(Data::skills, item->skill_id); + if (skill == nullptr) { + Output::Warning("UseItem: Can't use item %d skill with invalid ID %d", item->ID, item->skill_id); + return false; + } + } + + const Game_Actor* fixed_source = nullptr; + if (skill && skill->scope != RPG::Skill::Scope_self) { + fixed_source = GetHighestLeveledActorWhoCanUse(item); + if (fixed_source == nullptr) { + return false; + } + } + if (target) { - if (IsItemUsable(item_id, target)) { - was_used = target->UseItem(item_id); + const auto* source = fixed_source ? fixed_source : target; + if (IsItemUsable(item_id, source)) { + was_used = target->UseItem(item_id, source); } } else { - std::vector actors = GetActors(); - std::vector::iterator it; - for (it = actors.begin(); it != actors.end(); ++it) { - if (IsItemUsable(item_id, (*it))) { - was_used |= (*it)->UseItem(item_id); + for (auto* actor: GetActors()) { + const auto* source = fixed_source ? fixed_source : actor; + if (IsItemUsable(item_id, source)) { + was_used |= actor->UseItem(item_id, source); } } } @@ -632,11 +667,13 @@ bool Game_Party::IsAnyControllable() { return false; } -Game_Actor* Game_Party::GetHighestLeveledActorWhoCanAct() const { +Game_Actor* Game_Party::GetHighestLeveledActorWhoCanUse(const RPG::Item* item) const { Game_Actor* best = nullptr; for (auto* actor : GetActors()) { - if (actor->CanAct() && (best == nullptr || best->GetLevel() < actor->GetLevel())) { + if (actor->CanAct() + && actor->IsItemUsable(item->ID) + && (best == nullptr || best->GetLevel() < actor->GetLevel())) { best = actor; } } diff --git a/src/game_party.h b/src/game_party.h index 6f7a8c07bf..82ae5daa79 100644 --- a/src/game_party.h +++ b/src/game_party.h @@ -342,11 +342,13 @@ class Game_Party : public Game_Party_Base { bool IsAnyControllable(); /** - * Gets the actor with the highest level who can act. If there are many, choose the one with the earliest position in the group. + * Gets the actor with the highest level who can act and use the given item. If there are many, choose the one with the earliest position in the group. + * + * @param the item to check * * @return The first Highest leveled actor who can act. */ - Game_Actor* GetHighestLeveledActorWhoCanAct() const; + Game_Actor* GetHighestLeveledActorWhoCanUse(const RPG::Item*) const; private: const RPG::SaveInventory& data() const;