/****************************************************************************
* Copyright (C) 2015-2016 by the SotS Team *
* *
* This file is part of Sovereign of the Skies. *
* *
* Sovereign of the Skies is free software: you can redistribute it *
* and/or modify it *
* under the terms of the GNU Lesser General Public License as published *
* by the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version provided you include a copy of the *
* licence and this header. *
* *
* Sovereign of the Skies is distributed in the hope that it will be *
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with Sovereign of the Skies. *
* If not, see . *
****************************************************************************/
/**
* @file battle_help.c
* @author Sturmvogel
* @date 15 dec 2016
* @brief Some general helper methods for battle
*/
/* === INCLUDE === */
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/* === STATICS === */
/* from kds emerald battle engine upgrade */
u8 type_effectiveness_table[TYPE_FAIRY - 0x4][TYPE_FAIRY - 0x4] = {
{10, 10, 10, 10, 10, 05, 10, 00, 05, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, // normal
{20, 10, 05, 05, 10, 20, 05, 00, 20, 10, 10, 10, 10, 10, 05, 20, 10, 20, 05}, // fight
{10, 20, 10, 10, 10, 05, 20, 10, 05, 10, 10, 10, 20, 05, 10, 10, 10, 10, 10}, // flying
{10, 10, 10, 05, 05, 05, 10, 05, 00, 10, 10, 10, 20, 10, 10, 10, 10, 10, 20}, // poison
{10, 10, 00, 20, 10, 20, 05, 10, 20, 10, 20, 10, 05, 20, 10, 10, 10, 10, 10}, // ground
{10, 05, 20, 10, 05, 10, 20, 10, 05, 10, 20, 10, 10, 10, 10, 20, 10, 10, 10}, // rock
{10, 05, 05, 05, 10, 10, 10, 05, 05, 10, 05, 10, 20, 10, 20, 10, 10, 20, 05}, // bug
{00, 10, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10, 10, 20, 10, 10, 05, 10}, // ghost
{10, 10, 10, 10, 10, 20, 10, 10, 05, 10, 05, 05, 10, 05, 10, 20, 10, 10, 20}, // steel
{10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10}, // egg
{10, 10, 10, 10, 10, 05, 20, 10, 20, 10, 05, 05, 20, 10, 10, 20, 05, 10, 10}, // fire
{10, 10, 10, 10, 20, 20, 10, 10, 10, 10, 20, 05, 05, 10, 10, 10, 05, 10, 10}, // water
{10, 10, 05, 05, 20, 20, 05, 10, 05, 10, 05, 20, 05, 10, 10, 10, 05, 10, 10}, // grass
{10, 10, 20, 10, 00, 10, 10, 10, 10, 10, 10, 20, 05, 05, 10, 10, 05, 10, 10}, // electric
{10, 20, 10, 20, 10, 10, 10, 10, 05, 10, 10, 10, 10, 10, 05, 10, 10, 00, 10}, // psychic
{10, 10, 20, 10, 20, 10, 10, 10, 05, 10, 05, 05, 20, 10, 10, 05, 20, 10, 10}, // ice
{10, 10, 10, 10, 10, 10, 10, 10, 05, 10, 10, 10, 10, 10, 10, 10, 20, 10, 00}, // dragon
{10, 05, 10, 10, 10, 10, 10, 20, 10, 10, 10, 10, 10, 10, 20, 10, 10, 05, 05}, // dark
{10, 20, 10, 05, 10, 10, 10, 10, 05, 10, 05, 10, 10, 10, 10, 10, 20, 20, 10} // fairy
};
/* === IMPLEMENTATIONS === */
u16 battle_damage_type_effectiveness_update(u8 attacking_type, u8 defending_type, u8 atk_bank, u8 def_bank,
u16 chained_effect, u8 airstatus) {
u8 effect, atype = attacking_type, dtype = defending_type;
if (!chained_effect || atype == TYPE_EGG || dtype == TYPE_EGG)
return chained_effect;
if (atype >= TYPE_FAIRY)
atype = atype - 5;
if (dtype >= TYPE_FAIRY)
dtype = dtype - 5;
effect = type_effectiveness_table[atype][dtype];
if (custom_battle_elements.ptr->various.inverse_battle) {
if (effect == 20) {
effect = 5;
} else if (effect == 5 || effect == 0) {
effect = 20;
}
}
/* handle normal / fighting on ghost */
if ((((attacking_type == TYPE_NORMAL || attacking_type == TYPE_FIGHTING) && defending_type == TYPE_GHOST &&
((battle_participants[def_bank].status2.foresight))) ||
battle_participants[atk_bank].ability_id == ABILITY_SCRAPPY) &&
effect == 0) {
effect = 10;
}
/* handle other effectiveness changers here */
switch (effect) {
case 0:
chained_effect = 0;
break;
case 5:
chained_effect = chained_effect >> 1;
break;
case 20:
chained_effect = chained_effect << 1;
break;
}
return chained_effect;
}
u16 battle_apply_type_effectiveness(u16 chained_effect, u8 move_type, u8 target_bank, u8 atk_bank, u8 airstatus) {
u8 defender_type1 = battle_participants[target_bank].type1;
u8 defender_type2 = battle_participants[target_bank].type2;
/* set different types */
if (defender_type2 == defender_type1)
defender_type2 = TYPE_EGG;
chained_effect = battle_damage_type_effectiveness_update(move_type, defender_type1, atk_bank, target_bank,
chained_effect, airstatus);
chained_effect = battle_damage_type_effectiveness_update(move_type, defender_type2, atk_bank, target_bank,
chained_effect, airstatus);
return chained_effect;
}
u16 battle_type_effectiveness_calc(u16 move, u8 move_type, u8 atk_bank, u8 def_bank,
u8 effects_handling_and_recording) {
u16 chained_effect = 64;
// TODO: double_type moves
// TODO: get air status
chained_effect = battle_apply_type_effectiveness(chained_effect, move_type, def_bank, atk_bank, 2);
// TODO: save into structs
// TODO: effect_handling_and_recording
return chained_effect;
}
u8 battle_bank_has_type(u8 bank, u8 type) {
return battle_participants[bank].type1 == type || battle_participants[bank].type2 == type;
}
u8 battle_item_get_effect(u8 bank, u8 check_negating_effects) {
if (check_negating_effects) {
if (battle_participants[bank].ability_id == ABILITY_KLUTZ ||
custom_battle_elements.ptr->bank_affecting[bank].embargo)
return ITEM_EFFECT_NOEFFECT;
}
if (battle_participants[bank].held_item == ITEM_ENIGMABERRY) {
return battle_enigma_berry[bank].battle_effect_x12;
} else {
return item_get_x12(battle_participants[bank].held_item);
}
}
u8 battle_bank_is_poison_resistant(u8 bank, u8 self_inflicted) { // 0 == can poison
// 1 == is already poisoned
// 2 == has other major condition
// 3 == type doesn't allow it
// 4 == ability doesn't allow it
// 5 == safeguard protection
// 8 == misty terrain doesn't allow it !TODO!
if (battle_participants[bank].status.flags.poison || battle_participants[bank].status.flags.toxic_poison)
return 1;
if (battle_participants[bank].status.int_status)
return 2;
if (battle_bank_has_type(bank, TYPE_POISON) || battle_bank_has_type(bank, TYPE_STEEL))
return 3;
if (((battle_participants[bank].ability_id == ABILITY_IMMUNITY ||
(battle_participants[bank].ability_id == ABILITY_LEAF_GUARD &&
(battle_weather.flags.sun || battle_weather.flags.permament_sun || battle_weather.flags.harsh_sun)))))
return 4;
if (side_affecting_halfword[get_side_from_bank(bank)].safeguard_on && !self_inflicted)
return 5;
return 0;
}
u8 battle_count_party_pokemon(u8 bank) {
struct pokemon *poke;
if (get_side_from_bank(bank))
poke = &party_opponent[0];
else
poke = &party_player[0];
u8 usable_pokes = 0;
for (u8 i = 0; i < 6; i++) {
if (pokemon_get_attribute(&poke[i], ATTR_CURRENT_HP, 0) != 0 &&
pokemon_get_attribute(&poke[i], ATTR_IS_EGG, 0) != 1 &&
pokemon_get_attribute(&poke[i], ATTR_SPECIES, 0) != 0)
usable_pokes++;
}
return usable_pokes;
}