bool Game_BattleAlgorithm::Normal::Execute() { Reset(); int to_hit; float multiplier = 1; int crit_chance = source->GetCriticalHitChance(); if (source->GetType() == Game_Battler::Type_Ally) { Game_Actor* ally = static_cast<Game_Actor*>(source); int hit_chance = source->GetHitChance(); int weaponID = ally->GetWeaponId() - 1; if (weaponID == -1) { // No Weapon // Todo: Two Sword style animation = &Data::animations[Data::actors[ally->GetId() - 1].unarmed_animation - 1]; } else { animation = &Data::animations[Data::items[weaponID].animation_id - 1]; RPG::Item weapon = Data::items[weaponID]; hit_chance = weapon.hit; crit_chance += weapon.critical_hit; multiplier = GetAttributeMultiplier(weapon.attribute_set); } to_hit = (int)(100 - (100 - hit_chance)); if(weaponID != -1 && !Data::items[weaponID].ignore_evasion) { to_hit *= (1 + (1.0 * (*current_target)->GetAgi() / ally->GetAgi() - 1) / 2); } } else { // Source is Enemy int hit = source->GetHitChance(); to_hit = (int)(100 - (100 - hit) * (1 + (1.0 * (*current_target)->GetAgi() / source->GetAgi() - 1) / 2)); } // Damage calculation if (rand() % 100 < to_hit) { if (!source->IsCharged() && rand() % 100 < crit_chance) { critical_hit = true; } int effect = (source->GetAtk() / 2 - (*current_target)->GetDef() / 4); if (effect < 0) effect = 0; int act_perc = (rand() % 40) - 20; // Change rounded up int change = (int)(std::ceil(effect * act_perc / 100.0)); effect += change; effect *= multiplier; if(effect < 0) { effect = 0; } this->hp = (effect * (critical_hit ? 3 : 1) * (source->IsCharged() ? 2 : 1)) / ((*current_target)->IsDefending() ? 2 : 1); if ((*current_target)->GetHp() - this->hp <= 0) { // Death state killed_by_attack_damage = true; conditions.push_back(Data::states[0]); } else { if (source->GetType() == Game_Battler::Type_Ally) { int weaponID = static_cast<Game_Actor*>(source)->GetWeaponId() - 1; if (weaponID != -1) { RPG::Item item = Data::items[static_cast<Game_Actor*>(source)->GetWeaponId() - 1]; for (int i = 0; i < item.state_set.size(); i++) { if (item.state_set[i] && rand() % 100 < (item.state_chance * (*current_target)->GetStateProbability(Data::states[i].ID) / 100)) { if (item.state_effect) { healing = true; } conditions.push_back(Data::states[i]); } } } } } } else { this->success = false; return this->success; } this->success = true; return this->success; }
bool Game_BattleAlgorithm::Skill::Execute() { if (item && item->skill_id != skill.ID) { assert(false && "Item skill mismatch"); } Reset(); animation = skill.animation_id == 0 ? NULL : &Data::animations[skill.animation_id - 1]; this->success = false; this->healing = skill.scope == RPG::Skill::Scope_ally || skill.scope == RPG::Skill::Scope_party || skill.scope == RPG::Skill::Scope_self; if (skill.type == RPG::Skill::Type_normal || skill.type >= RPG::Skill::Type_subskill) { if (this->healing) { this->success = true; if (skill.affect_hp) this->hp = skill.power; if (skill.affect_sp) this->sp = skill.power; if (skill.affect_attack) this->attack = skill.power; if (skill.affect_defense) this->defense = skill.power; if (skill.affect_spirit) this->spirit = skill.power; if (skill.affect_agility) this->agility = skill.power; } else if (rand() % 100 < skill.hit) { this->success = true; int effect = skill.power + source->GetAtk() * skill.physical_rate / 20 + source->GetSpi() * skill.magical_rate / 40; if (!skill.ignore_defense) { effect -= (*current_target)->GetDef() * skill.physical_rate / 40 - (*current_target)->GetSpi() * skill.magical_rate / 80; } effect *= GetAttributeMultiplier(skill.attribute_effects); if(effect < 0) { effect = 0; } effect += rand() % (((effect * skill.variance / 10) + 1) - (effect * skill.variance / 20)); if (effect < 0) effect = 0; if (skill.affect_hp) { this->hp = effect / ((*current_target)->IsDefending() ? 2 : 1); if ((*current_target)->GetHp() - this->hp <= 0) { // Death state killed_by_attack_damage = true; conditions.push_back(Data::states[0]); } } if (skill.affect_sp) { this->sp = std::min<int>(effect, (*current_target)->GetSp()); } if (skill.affect_attack) this->attack = effect; if (skill.affect_defense) this->defense = effect; if (skill.affect_spirit) this->spirit = effect; if (skill.affect_agility) this->agility = agility; } for (int i = 0; i < (int) skill.state_effects.size(); i++) { if (!skill.state_effects[i]) continue; if (!healing && rand() % 100 >= skill.hit) continue; this->success = true; if (healing || rand() % 100 <= (*current_target)->GetStateProbability(Data::states[i].ID)) { conditions.push_back(Data::states[i]); } } } else if (skill.type == RPG::Skill::Type_switch) { switch_id = skill.switch_id; this->success = true; } else { assert(false && "Unsupported skill type"); } absorb = skill.absorb_damage; if (absorb && sp != -1) { if ((*current_target)->GetSp() == 0) { this->success = false; } } return this->success; }
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); return false; } bool cure_hp_percentage = false; bool was_used = false; if (skill->type == RPG::Skill::Type_normal || skill->type >= RPG::Skill::Type_subskill) { // Only takes care of healing skills outside of battle, // the other skill logic is in Game_BattleAlgorithm if (!(skill->scope == RPG::Skill::Scope_ally || skill->scope == RPG::Skill::Scope_party || skill->scope == RPG::Skill::Scope_self)) { return false; } // Calculate effect: float mul = GetAttributeMultiplier(skill->attribute_effects); int effect = skill->power; if (source != nullptr) { effect += source->GetAtk() * skill->physical_rate / 20 + source->GetSpi() * skill->magical_rate / 40; } effect *= mul; effect += (effect * Utils::GetRandomNumber(-skill->variance * 10, skill->variance * 10) / 100); if (effect < 0) effect = 0; // Cure states for (int i = 0; i < (int)skill->state_effects.size(); i++) { if (skill->state_effects[i]) { if (skill->reverse_state_effect) { was_used |= !HasState(Data::states[i].ID); AddState(Data::states[i].ID); } else { was_used |= HasState(Data::states[i].ID); RemoveState(Data::states[i].ID); // If Death is cured and HP is not selected, we set a bool so it later heals HP percentage if (i == 0 && !skill->affect_hp) { cure_hp_percentage = true; } } } } // Skills only increase hp and sp outside of battle if (effect > 0 && skill->affect_hp && !HasFullHp() && !IsDead()) { was_used = true; ChangeHp(effect); } else if (effect > 0 && cure_hp_percentage) { was_used = true; ChangeHp(GetMaxHp() * effect / 100); } if (effect > 0 && skill->affect_sp && !HasFullSp() && !IsDead()) { was_used = true; ChangeSp(effect); } } else if (skill->type == RPG::Skill::Type_teleport || skill->type == RPG::Skill::Type_escape) { Game_System::SePlay(skill->sound_effect); was_used = true; } else if (skill->type == RPG::Skill::Type_switch) { Game_System::SePlay(skill->sound_effect); Game_Switches.Set(skill->switch_id, true); was_used = true; } return was_used; }