diff --git a/src/game_actor.cpp b/src/game_actor.cpp index 0a2b480db5..006b4fffaa 100644 --- a/src/game_actor.cpp +++ b/src/game_actor.cpp @@ -156,17 +156,13 @@ bool Game_Actor::IsSkillUsable(int skill_id) const { for (size_t i = 0; i < skill->attribute_effects.size(); ++i) { bool required = skill->attribute_effects[i] && Data::attributes[i].type == RPG::Attribute::Type_physical; if (required) { - if (item && i < item->attribute_set.size()) { - if (!item->attribute_set[i]) { - return false; - } - } else if (item2 && i < item2->attribute_set.size()) { - if (!item2->attribute_set[i]) { - return false; - } - } else { - return false; + if (item && i < item->attribute_set.size() && item->attribute_set[i]) { + continue; } + if (item2 && i < item2->attribute_set.size() && item2->attribute_set[i]) { + continue; + } + return false; } } @@ -190,7 +186,7 @@ int Game_Actor::GetSpCostModifier() const { } int Game_Actor::CalculateSkillCost(int skill_id) const { - return Game_Battler::CalculateSkillCost(skill_id) / GetSpCostModifier(); + return std::ceil(Game_Battler::CalculateSkillCost(skill_id) / (float) GetSpCostModifier()); } bool Game_Actor::LearnSkill(int skill_id) { @@ -573,15 +569,25 @@ int Game_Actor::GetNextExp(int level) const { } int Game_Actor::GetStateProbability(int state_id) const { - int rate = 2; // C - default + int rate = 2, mul = 100; // C - default const uint8_t* r = ReaderUtil::GetElement(GetActor().state_ranks, state_id); if (r) { rate = *r; } + // This takes the armor of the character with the most resistance for that particular state + for (const auto equipment : GetWholeEquipment()) { + RPG::Item* item = ReaderUtil::GetElement(Data::items, equipment); + if (item != nullptr && (item->type == RPG::Item::Type_shield || item->type == RPG::Item::Type_armor + || item->type == RPG::Item::Type_helmet || item->type == RPG::Item::Type_accessory) + && state_id <= item->state_set.size() && item->state_set[state_id - 1]) { + mul = std::min(mul, 100 - item->state_chance); + } + } + // GetStateRate verifies the state_id - return GetStateRate(state_id, rate); + return GetStateRate(state_id, rate) * mul / 100; } int Game_Actor::GetAttributeModifier(int attribute_id) const { @@ -602,6 +608,16 @@ int Game_Actor::GetAttributeModifier(int attribute_id) const { } rate += *shift; + for (auto id_object : GetWholeEquipment()) { + RPG::Item *object = ReaderUtil::GetElement(Data::items, id_object); + if (object != nullptr && (object->type == RPG::Item::Type_shield || object->type == RPG::Item::Type_armor + || object->type == RPG::Item::Type_helmet || object->type == RPG::Item::Type_accessory) + && object->attribute_set.size() >= attribute_id && object->attribute_set[attribute_id - 1]) { + rate++; + break; + } + } + if (rate < 0) { rate = 0; } else if (rate > 4) { diff --git a/src/game_battle.cpp b/src/game_battle.cpp index 36b8e381d1..5ed2fc2bc7 100644 --- a/src/game_battle.cpp +++ b/src/game_battle.cpp @@ -153,7 +153,26 @@ bool Game_Battle::CheckWin() { } bool Game_Battle::CheckLose() { - return !Main_Data::game_party->IsAnyActive(); + if (!Main_Data::game_party->IsAnyActive()) + return true; + + // If there are active characters, but all of them are in a state with Restriction "Do Nothing" and 0% recovery probability, it's game over + // Physical recovery doesn't matter in this case + int character_number = 0; + std::vector actors; + + Main_Data::game_party->GetActiveBattlers(actors); + for (auto actor : actors) { + for (auto id_state : actor->GetInflictedStates()) { + RPG::State *state = ReaderUtil::GetElement(Data::states, id_state); + if (state->restriction == RPG::State::Restriction_do_nothing && state->auto_release_prob == 0) { + ++character_number; + break; + } + } + } + + return character_number == actors.size(); } Spriteset_Battle& Game_Battle::GetSpriteset() { diff --git a/src/game_battlealgorithm.cpp b/src/game_battlealgorithm.cpp index 25fbba4638..0d53f95271 100644 --- a/src/game_battlealgorithm.cpp +++ b/src/game_battlealgorithm.cpp @@ -421,6 +421,12 @@ void Game_BattleAlgorithm::AlgorithmBase::GetResultMessages(std::vectorIsDead()); + return GetTarget()->Exists(); } int Game_BattleAlgorithm::AlgorithmBase::GetSourceAnimationState() const { @@ -843,7 +849,7 @@ void Game_BattleAlgorithm::Normal::Apply() { Game_Actor* src = static_cast(source); const RPG::Item* weapon = ReaderUtil::GetElement(Data::items, src->GetWeaponId()); if (weapon) { - source->ChangeSp(-weapon->sp_cost / src->GetSpCostModifier()); + source->ChangeSp(std::ceil(-weapon->sp_cost / (float) src->GetSpCostModifier())); } } } @@ -1021,8 +1027,12 @@ bool Game_BattleAlgorithm::Skill::Execute() { this->success = (GetAffectedHp() != -1 && !IsAbsorb()) || (GetAffectedHp() > 0 && IsAbsorb()) || GetAffectedSp() > 0 || GetAffectedAttack() > 0 || GetAffectedDefense() > 0 || GetAffectedSpirit() > 0 || GetAffectedAgility() > 0; + + if (IsAbsorb() && !success) + return this->success; } + // Conditions: for (int i = 0; i < (int) skill.state_effects.size(); i++) { if (!skill.state_effects[i]) continue; @@ -1044,23 +1054,17 @@ bool Game_BattleAlgorithm::Skill::Execute() { assert(false && "Unsupported skill type"); } - if (IsAbsorb() && sp != -1) { - if (GetTarget()->GetSp() == 0) { - this->success = false; - } - } - return this->success; } void Game_BattleAlgorithm::Skill::Apply() { AlgorithmBase::Apply(); - if (item) { - Main_Data::game_party->ConsumeItemUse(item->ID); - } - else { - if (first_attack) { + if (IsFirstAttack()) { + if (item) { + Main_Data::game_party->ConsumeItemUse(item->ID); + } + else { source->ChangeSp(-source->CalculateSkillCost(skill.ID)); } } @@ -1129,6 +1133,10 @@ const RPG::Sound* Game_BattleAlgorithm::Skill::GetStartSe() const { } } +const RPG::Sound* Game_BattleAlgorithm::Skill::GetResultSe() const { + return !success && skill.failure_message != 3 ? NULL : AlgorithmBase::GetResultSe(); +} + void Game_BattleAlgorithm::Skill::GetResultMessages(std::vector& out) const { if (!success) { switch (skill.failure_message) { @@ -1304,7 +1312,8 @@ int Game_BattleAlgorithm::Item::GetSourceAnimationState() const { } void Game_BattleAlgorithm::Item::GetResultMessages(std::vector& out) const { - AlgorithmBase::GetResultMessages(out); + if (success) + AlgorithmBase::GetResultMessages(out); } const RPG::Sound* Game_BattleAlgorithm::Item::GetStartSe() const { diff --git a/src/game_battlealgorithm.h b/src/game_battlealgorithm.h index 3de8f43cf3..1fc3c068e6 100644 --- a/src/game_battlealgorithm.h +++ b/src/game_battlealgorithm.h @@ -391,6 +391,7 @@ class Skill : public AlgorithmBase { std::string GetStartMessage() const override; int GetSourceAnimationState() const override; const RPG::Sound* GetStartSe() const override; + const RPG::Sound* GetResultSe() const override; void GetResultMessages(std::vector& out) const override; int GetPhysicalDamageRate() const override; bool IsReflected() const override; diff --git a/src/game_battler.cpp b/src/game_battler.cpp index 8f6e503f29..853b4424e0 100644 --- a/src/game_battler.cpp +++ b/src/game_battler.cpp @@ -458,11 +458,11 @@ void Game_Battler::RemoveBattleStates() { // If death is non-permanent change HP to 1 if (IsDead() && non_permanent(1)) { - ChangeHp(1); + RemoveState(1); } - for (size_t i = 0; i < states.size(); ++i) { - if (non_permanent(i + 1)) { + for (size_t i = 1; i < states.size(); ++i) { + if (non_permanent(i + 1) || ReaderUtil::GetElement(Data::states, i + 1)->auto_release_prob > 0) { states[i] = 0; } } diff --git a/src/scene_battle.cpp b/src/scene_battle.cpp index e18d7c80ef..77ea236390 100644 --- a/src/scene_battle.cpp +++ b/src/scene_battle.cpp @@ -114,6 +114,10 @@ void Scene_Battle::TransitionOut() { } } +void Scene_Battle::DrawBackground() { + DisplayUi->CleanDisplay(); +} + void Scene_Battle::CreateUi() { std::vector commands; commands.push_back(Data::terms.battle_fight); diff --git a/src/scene_battle.h b/src/scene_battle.h index d2b8459281..0cf3f746e6 100644 --- a/src/scene_battle.h +++ b/src/scene_battle.h @@ -62,6 +62,7 @@ class Scene_Battle : public Scene { void TransitionIn() override; void TransitionOut() override; + void DrawBackground() override; enum State { /** Battle has started (Display encounter message) */ diff --git a/src/scene_battle_rpg2k.cpp b/src/scene_battle_rpg2k.cpp index af65071efe..0e178f32a4 100644 --- a/src/scene_battle_rpg2k.cpp +++ b/src/scene_battle_rpg2k.cpp @@ -335,7 +335,11 @@ bool Scene_Battle_Rpg2k::ProcessBattleAction(Game_BattleAlgorithm::AlgorithmBase Sprite_Battler* source_sprite; Sprite_Battler* target_sprite; - if (battle_action_wait) { + if (Input::IsPressed(Input::DECISION)) { + --battle_action_wait; + } + + if (battle_action_wait > 0) { if (--battle_action_wait) { return false; } @@ -362,6 +366,10 @@ bool Scene_Battle_Rpg2k::ProcessBattleAction(Game_BattleAlgorithm::AlgorithmBase } } + if (Input::IsPressed(Input::CANCEL)) { + return false; + } + switch (battle_action_state) { case BattleActionState_Start: battle_action_wait = GetDelayForWindow(); @@ -539,8 +547,7 @@ void Scene_Battle_Rpg2k::ProcessInput() { if (Input::IsTriggered(Input::DECISION)) { switch (state) { case State_Start: - // Skip current message - encounter_message_sleep_until = Player::GetFrames(); + // no-op break; case State_SelectOption: // Interpreter message boxes pop up in this state @@ -686,6 +693,10 @@ void Scene_Battle_Rpg2k::Escape() { begin_escape = false; } else { + if (Input::IsPressed(Input::DECISION)) { + ++escape_counter; + } + ++escape_counter; if (escape_counter > 60) { @@ -874,6 +885,10 @@ bool Scene_Battle_Rpg2k::DisplayMonstersInMessageWindow() { encounter_message_first_monster = false; } + if (Input::IsPressed(Input::DECISION)) { + --encounter_message_sleep_until; + } + if (encounter_message_sleep_until > -1) { if (Player::GetFrames() >= encounter_message_sleep_until) { // Sleep over @@ -1000,7 +1015,9 @@ bool Scene_Battle_Rpg2k::CheckWin() { Game_Message::texts.push_back(Data::terms.victory + Player::escape_symbol + "|"); std::stringstream ss; - PushExperienceGainedMessage(exp); + if (exp > 0) { + PushExperienceGainedMessage(exp); + } if (money > 0) { PushGoldReceivedMessage(money); } diff --git a/src/scene_battle_rpg2k3.cpp b/src/scene_battle_rpg2k3.cpp index ceef6cd6bb..6ea61a5ad1 100644 --- a/src/scene_battle_rpg2k3.cpp +++ b/src/scene_battle_rpg2k3.cpp @@ -983,8 +983,10 @@ bool Scene_Battle_Rpg2k3::CheckWin() { std::string space = Player::IsRPG2k3E() ? " " : ""; std::stringstream ss; - ss << exp << space << Data::terms.exp_received; - Game_Message::texts.push_back(ss.str()); + if (exp > 0) { + ss << exp << space << Data::terms.exp_received; + Game_Message::texts.push_back(ss.str()); + } if (money > 0) { ss.str(""); ss << Data::terms.gold_recieved_a << " " << money << Data::terms.gold << Data::terms.gold_recieved_b;