/****************************************************************************
* 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;
}