Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- typedef struct {
- struct {
- unsigned char id;
- unsigned char national_dex;
- unsigned char typenum1, typenum2;
- struct small_stats {
- unsigned char hp, attack, defense, special_attack, special_defense, speed;
- } base_stats;
- } species;
- unsigned char level;
- unsigned experience;
- struct small_stats ivs;
- struct stats {
- unsigned short hp, attack, defense, special_attack, special_defense, speed;
- } evs;
- struct {
- unsigned char id;
- unsigned char pp;
- unsigned char pp_ups;
- } moves[4];
- } Pokemon;
- struct {
- unsigned char power;
- signed char effect_code;
- unsigned char hit_chance; // out of 256
- unsigned char type;
- } move_data[] = {
- { 0, 0, 0, 0},
- { 40, 0, 255, 0},
- { 50, -1, 255, 0},
- { 15, 29, 216, 0},
- { 18, 29, 216, 0},
- { 80, 0, 216, 0},
- { 40, 16, 255, 0},
- { 75, 4, 255, 20},
- { 75, 5, 255, 25},
- { 75, 6, 255, 23},
- { 40, 0, 255, 0},
- { 55, 0, 255, 0},
- { 1, 38, 76, 0},
- { 80, 39, 191, 0},
- { 0, 50, 255, 0},
- { 50, 0, 242, 0},
- { 40, 0, 255, 0},
- { 35, 0, 255, 2},
- { 0, 28, 216, 0},
- { 70, 43, 242, 2},
- { 15, 42, 191, 0},
- { 80, 0, 191, 0},
- { 35, 0, 255, 22},
- { 65, 37, 255, 0},
- { 30, 44, 255, 1},
- {120, 0, 191, 0},
- { 70, 45, 242, 1},
- { 60, 37, 216, 1},
- { 0, 22, 255, 0},
- { 70, 37, 255, 0},
- { 65, 0, 255, 0},
- { 15, 29, 216, 0},
- { 1, 38, 76, 0},
- { 35, 0, 242, 0},
- { 85, 36, 255, 0},
- { 15, 42, 216, 0},
- { 90, 48, 216, 0},
- { 90, 27, 255, 0},
- {100, 48, 255, 0},
- { 0, 19, 255, 0},
- { 15, 2, 255, 3},
- { 25, 75, 255, 7},
- { 14, 29, 216, 7},
- { 0, 19, 255, 0},
- { 60, 31, 255, 0},
- { 0, 18, 255, 0},
- { 0, 28, 255, 0},
- { 0, 32, 140, 0},
- { 0, 49, 140, 0},
- { 20, 41, 229, 0}, // set power to 20 to help calculations
- { 0, 86, 140, 0},
- { 40, 69, 255, 3},
- { 40, 4, 255, 20},
- { 95, 4, 255, 20},
- { 0, 46, 255, 25},
- { 40, 0, 255, 21},
- {120, 0, 204, 21},
- { 95, 0, 255, 21},
- { 95, 5, 255, 25},
- {120, 5, 229, 25},
- { 65, 49, 255, 24},
- { 65, 71, 255, 21},
- { 65, 68, 255, 25},
- {150, 80, 229, 0},
- { 35, 0, 255, 2},
- { 80, 0, 255, 2},
- { 80, 48, 204, 1},
- { 50, 37, 229, 1},
- { 1, -7, 255, 1},
- { 1, -4, 255, 1},
- { 80, 0, 255, 0},
- { 20, 3, 255, 22},
- { 40, 3, 255, 22},
- { 0, 84, 229, 22},
- { 0, 12, 255, 0},
- { 55, -1, 242, 22},
- {120, 39, 255, 22},
- { 0, 66, 191, 3},
- { 0, 67, 191, 22},
- { 0, 32, 191, 22},
- { 70, 27, 255, 22},
- { 0, 20, 242, 7},
- { 40, 41, 255, 26}, // set power to 40 to help calculations
- { 15, 42, 178, 20},
- { 40, 6, 255, 23},
- { 95, 6, 255, 23},
- { 0, 67, 255, 23},
- {120, 6, 178, 23},
- { 50, 0, 165, 5},
- {100, 0, 255, 4},
- { 1, 38, 76, 4},
- {100, 39, 255, 4},
- { 0, -2, 216, 3},
- { 50, 76, 255, 24},
- { 90, 71, 255, 24},
- { 0, 32, 153, 24},
- { 0, 10, 255, 24},
- { 0, 52, 255, 24},
- { 40, -3, 255, 0},
- { 20, 81, 255, 0},
- { 0, 28, 255, 24},
- { 0, -4, 255, 8},
- { 0, 82, 255, 0},
- { 0, 59, 216, 0},
- { 0, 15, 255, 0},
- { 0, 56, 255, 0},
- { 0, 11, 255, 0},
- { 0, 15, 255, 0},
- { 0, 22, 255, 0},
- { 0, 49, 255, 8},
- { 0, 11, 255, 21},
- { 0, 11, 255, 0},
- { 0, 51, 255, 24},
- { 0, 64, 255, 24},
- { 0, 25, 255, 25},
- { 0, 65, 255, 24},
- { 0, 47, 255, 0},
- { 0, 26, 255, 0},
- { 0, 83, 255, 0},
- { 0, 9, 255, 2},
- {130, 7, 255, 0},
- {100, 0, 191, 0},
- { 20, 36, 255, 8},
- { 20, 33, 178, 3},
- { 65, 33, 255, 3},
- { 65, 31, 216, 4},
- {120, 34, 216, 20},
- { 80, 0, 255, 21},
- { 35, 42, 191, 21},
- { 60, 17, 255, 0},
- {100, 39, 255, 0},
- { 20, 29, 255, 0},
- { 10, 70, 255, 0},
- { 0, 53, 255, 24},
- { 0, 22, 204, 24},
- { 0, 56, 255, 0},
- { 85, 45, 229, 1},
- { 0, 67, 191, 0},
- {100, 8, 255, 24},
- { 0, 66, 140, 3},
- { 15, 29, 216, 0},
- { 20, 3, 255, 7},
- { 0, 32, 191, 0},
- {140, 39, 229, 2},
- { 0, 57, 255, 0},
- { 20, 70, 255, 21},
- { 70, 0, 255, 0},
- { 0, 32, 255, 22},
- { 0, 22, 178, 0},
- { 1, -5, 204, 24},
- { 0, 85, 255, 0},
- { 0, 51, 255, 3},
- { 90, -1, 216, 21},
- {170, 7, 255, 0},
- { 18, 29, 204, 0},
- { 50, 44, 229, 4},
- { 0, -6, 255, 24},
- { 75, 0, 229, 5},
- { 80, 31, 229, 0},
- { 0, 10, 255, 0},
- { 0, 24, 255, 0},
- { 80, 0, 255, 0},
- { 1, 40, 229, 0},
- { 70, -1, 255, 0},
- { 0, 79, 255, 0},
- { 50, 48, 255, 0}
- };
- // assign power-like values to various effects that moves may have
- #define POISON_VALUE 15
- #define PARALYSIS_VALUE 10
- #define SLEEP_VALUE 20
- #define BURN_VALUE 15
- #define FREEZE_VALUE 100
- #define CONFUSION_VALUE 30
- #define STAT_UP_VALUE 5
- #define STAT_DOWN_VALUE 5
- #define SCREEN_VALUE 20
- #define FLINCH_VALUE 15
- #define FAINT_VALUE 300
- #define HEAL_VALUE 80
- #define VULNERABLE_TURN_VALUE 15
- #define SUBSTITUTE_VALUE 30
- #define LEECH_SEED_VALUE 20
- #define DISABLE_VALUE 20
- #define PRIORITY_VALUE 5
- #define FLAG_DANGEROUS (1 << 0) /* the user will probably hurt itself just by having this move */
- #define FLAG_BAD_MOVE_CHOICE (1 << 1) /* the user will probably use this move incorrectly and waste a turn */
- #define FLAG_IGNORE (1 << 2) /* this move should not be taken into account when assessing damaging potential */
- #define FLAG_NO_STAB (1 << 3) /* the user will not get STAB reliably due to this move existing */
- #define FLAG_IGNORE_STAB (1 << 4) /* this move cannot get STAB */
- #define FLAG_EXACT_DAMAGE (1 << 5) /* the computed move power is this move's exact damage output */
- #define FLAG_TRANSFORM (1 << 6) /* this move makes the user adopt its opponent's stats and moves */
- #define FLAG_LEVEL_DAMAGE (1 << 7) /* this move's damage is equal to the level of the user */
- #define FLAG_HIGH_CRIT_RATIO (1 << 8) /* this move has a high critical hit ratio */
- #define FLAG_LOW_CRIT_CHANCE (1 << 9) /* a mon with this move will have a low crit chance, since it's likely to use the move and lower its own crit ratio */
- #define FLAG_NO_CRITICALS (1 << 10) /* this attack cannot ever result in a critical hit */
- struct move_effect_data {
- unsigned short flags;
- short multiply_offset; // implicit 256 denominator
- int add_offset; // implicit 256 denominator
- };
- struct move_effect_data effect_code_data[] = {
- // note that all omitted fields default to zero
- {0}, // all fields zero
- {0}, // unused
- {.add_offset = POISON_VALUE * 51},
- {.multiply_offset = 128},
- {.add_offset = BURN_VALUE * 25},
- {.add_offset = FREEZE_VALUE * 25},
- {.add_offset = PARALYSIS_VALUE * 25},
- {.multiply_offset = 256, .add_offset = -FAINT_VALUE * 256, .flags = FLAG_DANGEROUS},
- {.multiply_offset = -192, .flags = FLAG_BAD_MOVE_CHOICE},
- {.flags = FLAG_IGNORE},
- {.add_offset = STAT_UP_VALUE * 256},
- {.add_offset = STAT_UP_VALUE * 256},
- {.add_offset = STAT_UP_VALUE * 256},
- {.add_offset = STAT_UP_VALUE * 256},
- {.add_offset = STAT_UP_VALUE * 256},
- {.add_offset = STAT_UP_VALUE * 256},
- {0}, // same as no effect
- {.multiply_offset = 13}, // +5% for perfect accuracy
- {.add_offset = STAT_DOWN_VALUE * 256},
- {.add_offset = STAT_DOWN_VALUE * 256},
- {.add_offset = STAT_DOWN_VALUE * 256},
- {.add_offset = STAT_DOWN_VALUE * 256},
- {.add_offset = STAT_DOWN_VALUE * 256},
- {.add_offset = STAT_DOWN_VALUE * 256},
- {.flags = FLAG_IGNORE | FLAG_NO_STAB},
- {.flags = FLAG_BAD_MOVE_CHOICE},
- {.flags = FLAG_IGNORE | FLAG_BAD_MOVE_CHOICE},
- {.add_offset = -CONFUSION_VALUE * 73}, // will only confuse self after 3.5 turns in average
- {.flags = FLAG_IGNORE | FLAG_BAD_MOVE_CHOICE},
- {.multiply_offset = 2 * 256}, // * 3
- {0}, // unused
- {.add_offset = FLINCH_VALUE * 25},
- {.add_offset = SLEEP_VALUE * 256},
- {.add_offset = POISON_VALUE * 102},
- {.add_offset = BURN_VALUE * 76},
- {0}, // unused
- {.add_offset = PARALYSIS_VALUE * 76},
- {.add_offset = FLINCH_VALUE * 76},
- {.multiply_offset = -256, .add_offset = FAINT_VALUE * 256, .flags = FLAG_BAD_MOVE_CHOICE | FLAG_IGNORE_STAB | FLAG_NO_CRITICALS},
- {.multiply_offset = -128, .add_offset = -VULNERABLE_TURN_VALUE * 256},
- {.multiply_offset = -256, .add_offset = FAINT_VALUE * 64, .flags = FLAG_IGNORE_STAB | FLAG_NO_CRITICALS},
- {.flags = FLAG_EXACT_DAMAGE | FLAG_IGNORE_STAB | FLAG_NO_CRITICALS},
- {.multiply_offset = 2 * 256}, // * 3
- {0}, // wasted turn compensates for two-turn move
- {.multiply_offset = 256},
- {0}, // recoil is 1 HP, which doesn't really matter and we can ignore it
- {.flags = FLAG_BAD_MOVE_CHOICE},
- {.flags = FLAG_BAD_MOVE_CHOICE | FLAG_LOW_CRIT_CHANCE},
- {.multiply_offset = -64},
- {.add_offset = CONFUSION_VALUE * 256},
- {.add_offset = 2 * STAT_UP_VALUE * 256},
- {.add_offset = 2 * STAT_UP_VALUE * 256},
- {.add_offset = 2 * STAT_UP_VALUE * 256},
- {.add_offset = 2 * STAT_UP_VALUE * 256},
- {.add_offset = 2 * STAT_UP_VALUE * 256},
- {.add_offset = 2 * STAT_UP_VALUE * 256},
- {.add_offset = HEAL_VALUE * 256, .flags = FLAG_IGNORE_STAB},
- {.flags = FLAG_TRANSFORM}, // we can't use FLAG_IGNORE on Transform because it will usually be the mon's only move
- {.add_offset = 2 * STAT_DOWN_VALUE * 256},
- {.add_offset = 2 * STAT_DOWN_VALUE * 256},
- {.add_offset = 2 * STAT_DOWN_VALUE * 256},
- {.add_offset = 2 * STAT_DOWN_VALUE * 256},
- {.add_offset = 2 * STAT_DOWN_VALUE * 256},
- {.add_offset = 2 * STAT_DOWN_VALUE * 256},
- {.add_offset = SCREEN_VALUE * 256, .flags = FLAG_IGNORE_STAB},
- {.add_offset = SCREEN_VALUE * 256, .flags = FLAG_IGNORE_STAB},
- {.add_offset = POISON_VALUE * 256},
- {.add_offset = PARALYSIS_VALUE * 256},
- {.add_offset = STAT_DOWN_VALUE * 85},
- {.add_offset = STAT_DOWN_VALUE * 85},
- {.add_offset = STAT_DOWN_VALUE * 85},
- {.add_offset = STAT_DOWN_VALUE * 85},
- {0}, // unused
- {0}, // unused
- {0}, // unused
- {0}, // unused
- {.add_offset = CONFUSION_VALUE * 25},
- {.multiply_offset = 256, .add_offset = POISON_VALUE * 51},
- {0}, // unused
- {.add_offset = SUBSTITUTE_VALUE * 256},
- {.multiply_offset = -128, .add_offset = -VULNERABLE_TURN_VALUE * 256},
- {.multiply_offset = 128, .flags = FLAG_DANGEROUS}, // we can expect the average power gain for Rage to be +50%, but it's a bad idea anyway
- {.flags = FLAG_IGNORE}, // Mimic is just a pain to handle
- {.add_offset = 40 * 256, .flags = FLAG_BAD_MOVE_CHOICE}, // 40 power is a reasonable average
- {.add_offset = LEECH_SEED_VALUE * 256},
- {.multiply_offset = -256, .flags = FLAG_BAD_MOVE_CHOICE | FLAG_IGNORE_STAB},
- {.add_offset = DISABLE_VALUE * 256}
- };
- struct move_effect_data custom_effect_data[] = {
- // negative (made up) effect codes go here
- {.flags = FLAG_HIGH_CRIT_RATIO}, // -1: high crit ratio
- {.add_offset = POISON_VALUE * 640}, // -2: toxic (assume poison to be 2.5x as effective)
- {.add_offset = PRIORITY_VALUE * 256}, // -3: quick attack
- {.flags = FLAG_LEVEL_DAMAGE | FLAG_IGNORE_STAB | FLAG_NO_CRITICALS}, // -4: level-based move damage
- {.multiply_offset = -64, .flags = FLAG_LEVEL_DAMAGE | FLAG_IGNORE_STAB | FLAG_NO_CRITICALS}, // -5: psywave (deals 75% of level in average)
- {.add_offset = HEAL_VALUE * 256, .flags = FLAG_BAD_MOVE_CHOICE}, // -6: rest, scored as any heal move but the AI may use it at really bad times
- {.add_offset = 20 * 256, .flags = FLAG_BAD_MOVE_CHOICE | FLAG_NO_CRITICALS} // -7: counter, will deal 20 pow in average, but it's usually a bad choice in gen 1
- };
- unsigned char square_root (unsigned short value) {
- // square roots the gen 1/2 way
- if (value < 3) return value;
- if (value > 64516) return 255;
- unsigned char result;
- for (result = 2; (result * result) < value; result ++);
- return result;
- }
- unsigned short calculate_stat (unsigned char level, unsigned char base, unsigned char DV, unsigned short stat_exp, int is_HP) {
- // remember that shifts truncate! 15 >> 2 is 3, not 3.75
- unsigned growth = 2 * (base + DV) + (square_root(stat_exp) >> 2);
- if (is_HP) growth += 100;
- return (is_HP ? 10 : 5) + growth * level / 100; // also truncates
- }
- struct stats calculate_stats (Pokemon pokemon) {
- return (struct stats) {
- .hp = calculate_stat(pokemon.level, pokemon.species.base_stats.hp, pokemon.ivs.hp, pokemon.evs.hp, 1),
- .attack = calculate_stat(pokemon.level, pokemon.species.base_stats.attack, pokemon.ivs.attack, pokemon.evs.attack, 0),
- .defense = calculate_stat(pokemon.level, pokemon.species.base_stats.defense, pokemon.ivs.defense, pokemon.evs.defense, 0),
- .speed = calculate_stat(pokemon.level, pokemon.species.base_stats.speed, pokemon.ivs.speed, pokemon.evs.speed, 0),
- .special_attack = calculate_stat(pokemon.level, pokemon.species.base_stats.special_attack, pokemon.ivs.special_attack, pokemon.evs.special_attack, 0),
- .special_defense = calculate_stat(pokemon.level, pokemon.species.base_stats.special_defense, pokemon.ivs.special_defense, pokemon.evs.special_defense, 0)
- };
- }
- struct move_effect_data get_move_effect_data (unsigned char move) {
- int effect_code = move_data[move].effect_code;
- if (effect_code >= 0) return effect_code_data[effect_code];
- return custom_effect_data[~effect_code];
- }
- unsigned short get_move_flags (unsigned char move) {
- return get_move_effect_data(move).flags;
- }
- unsigned short get_mon_flags (Pokemon pkmn) {
- return get_move_flags(pkmn.moves -> id) | get_move_flags(pkmn.moves[1].id) | get_move_flags(pkmn.moves[2].id) | get_move_flags(pkmn.moves[3].id);
- }
- unsigned long long calculate_move_power_rating (unsigned char move, Pokemon attacker) {
- // (0.4 * level + 2) * attack stat * power * accuracy, adjusted for crit hit change
- // will contain an implicit shift of 24
- struct stats stats = calculate_stats(attacker);
- struct move_effect_data effect = get_move_effect_data(move);
- int power = move_data[move].power * move_data[move].hit_chance * (256 + effect.multiply_offset);
- unsigned short global_flags = get_mon_flags(attacker);
- unsigned short crit_chance = attacker.species.base_stats.speed >> 1;
- unsigned short attack_stat = (move_data[move].type >= 20) ? stats.special_attack : stats.attack;
- if (effect.flags & FLAG_HIGH_CRIT_RATIO) crit_chance <<= 3;
- if (global_flags & FLAG_LOW_CRIT_CHANCE) crit_chance >>= 2;
- if (crit_chance > 255) crit_chance = 255;
- if (effect.flags & FLAG_LEVEL_DAMAGE) {
- effect.flags |= FLAG_EXACT_DAMAGE;
- power = attacker.level * (256 + effect.multiply_offset) * move_data[move].hit_chance;
- }
- if (effect.flags & FLAG_EXACT_DAMAGE) {
- // at low levels, exact damage is a lot more tempting than at high levels
- // to account for this fact, we take a fixed attack stat value of 100 for damage calculation and pretend they are variable power moves
- effect.flags |= FLAG_IGNORE_STAB | FLAG_NO_CRITICALS;
- attack_stat = 100;
- }
- if (effect.flags & FLAG_NO_CRITICALS) crit_chance = 0;
- if (
- ((move_data[move].type == attacker.species.typenum1) || (move_data[move].type == attacker.species.typenum2)) &&
- !((effect.flags & FLAG_IGNORE_STAB) || (global_flags & FLAG_NO_STAB))
- ) power += power >> 1;
- power += effect.add_offset * move_data[move].hit_chance; // add this AFTER calculating STAB!
- if (power <= 0) return 0;
- unsigned long long regular_damage, critical_damage;
- regular_damage = critical_damage = (unsigned long long) attack_stat * power;
- regular_damage *= 2 * attacker.level / 5 + 5;
- critical_damage *= 4 * attacker.level / 5 + 5;
- return critical_damage * crit_chance + regular_damage * (256 - crit_chance);
- }
- unsigned calculate_transform_rating (Pokemon attacker) {
- // will contain an implicit shift of 24
- // treat it like a generic 80 base power, no effect, 99.6% accuracy STAB attack
- // coming from a mon the same level as the attacker with 85 base all stats, 7 DVs, +32 @L100 from stat exp
- unsigned long long base_power = 0x778800ULL * (5 + attacker.level * 54 / 25); // repeat the calculations above, but hardcode the values
- unsigned long long regular_damage = base_power * (2 * attacker.level / 5 + 5);
- unsigned long long critical_damage = base_power * (4 * attacker.level / 5 + 5);
- return critical_damage * 42 + regular_damage * 214;
- }
- void sort_pair (unsigned long long * lower, unsigned long long * higher) {
- if (*lower <= *higher) return;
- unsigned long long temp = *lower;
- *lower = *higher;
- *higher = temp;
- }
- unsigned char count_moves_with_flag (Pokemon pkmn, unsigned short flag) {
- unsigned char p, result = 0;
- for (p = 0; p < 4; p ++) {
- if (!pkmn.moves[p].id) continue;
- if (get_move_flags(pkmn.moves[p].id) & flag) result ++;
- }
- return result;
- }
- unsigned long long calculate_attacker_rating (Pokemon attacker) {
- // will contain an implicit shift of 32
- unsigned long long move_ratings[4];
- unsigned char p, move_count = 0;
- unsigned short flags;
- for (p = 0; p < 4; p ++) {
- if (!attacker.moves[p].id) continue;
- flags = get_move_flags(attacker.moves[p].id);
- if (flags & FLAG_IGNORE) continue;
- move_ratings[move_count ++] = (flags & FLAG_TRANSFORM) ? calculate_transform_rating(attacker) : calculate_move_power_rating(attacker.moves[p].id, attacker);
- }
- if (!move_count) return 0;
- // simple swap-based sort because there are only four entries anyway
- switch (move_count) {
- case 4:
- sort_pair(move_ratings + 3, move_ratings);
- sort_pair(move_ratings + 3, move_ratings + 1);
- sort_pair(move_ratings + 3, move_ratings + 2);
- case 3:
- sort_pair(move_ratings + 2, move_ratings);
- sort_pair(move_ratings + 2, move_ratings + 1);
- case 2:
- sort_pair(move_ratings + 1, move_ratings);
- }
- // weights: 9, 4, 2, 1. If the mon has less than four moves, the first move's weight is increased to keep the total at 16
- unsigned long long weighted_total = *move_ratings << (4 - move_count);
- for (p = 0; p < move_count; p ++) weighted_total += move_ratings[p] << (p ^ 3); // note that p ^ 3 is the same as 3 - p here
- // take away 1/16 for every bad move the mon has
- return weighted_total * (16 - count_moves_with_flag(attacker, FLAG_BAD_MOVE_CHOICE));
- }
- unsigned long long calculate_defender_rating (Pokemon defender) {
- // must contain an implicit shift of 32 to be compatible with calculate_attacker_rating
- struct stats stats = calculate_stats(defender);
- unsigned long long rating = stats.defense + stats.special_defense; // start with the good old stat average. Accumulated shift: 1
- unsigned short low_stat = (stats.defense > stats.special_defense) ? stats.special_defense : stats.defense;
- unsigned short high_stat = rating - low_stat; // simple trick here
- rating *= stats.hp; // in two steps so there is no overflow
- rating *= defender.species.base_stats.speed + 452; // offset of 1/512 for every base speed point away from 70. Accumulated shift: 10
- rating *= 20; // adjustment factor: 50 for the damage formula, times 40% to make it equivalent to level
- unsigned short stat_ratio = ((unsigned) low_stat << 16) / high_stat;
- // factor in the stat spread, so mons like Chansey get their defensive rating lowered (because there is a weak point). Accumulated shift: 18
- if ((stat_ratio > 65025) || !stat_ratio) // stat_ratio = 0 indicates low_stat = high_stat and some problematic overflow
- rating <<= 8;
- else
- rating *= square_root(stat_ratio);
- unsigned char total_moves = 0, dangerous_moves = 0, self_damaging_moves = 0;
- struct move_effect_data effect;
- unsigned char p;
- for (p = 0; p < 4; p ++) {
- if (!defender.moves[p].id) continue;
- total_moves ++;
- effect = get_move_effect_data(defender.moves[p].id);
- if (effect.flags & FLAG_DANGEROUS) dangerous_moves ++;
- if (effect.add_offset < 0) self_damaging_moves ++; // negative add mod means that the move hurts the user somehow
- }
- if ((total_moves == dangerous_moves) && (total_moves == self_damaging_moves)) return 0; // this mon is suicidal and should not be used at all
- total_moves --; // easier indexing
- rating *= 128 - dangerous_moves * total_moves[(unsigned char []) {128, 64, 43, 32}]; // dangerous move chance out of 128. Accumulated shift: 25
- rating *= 128 - self_damaging_moves * total_moves[(unsigned char []) {60, 30, 20, 15}]; // 1 - (15/32 * self damage chance). Accumulated shift: 32
- // nothing interesting to do here now
- return rating;
- }
- unsigned calculate_overall_rating (Pokemon pkmn) {
- struct stats stats = calculate_stats(pkmn);
- unsigned long long attack_rating = calculate_attacker_rating(pkmn), defense_rating = calculate_defender_rating(pkmn);
- // faster mons attack first, hence the weights here. Note that they add a shift of 10
- unsigned short attack_weight = (stats.speed * 100 / pkmn.level) + 320;
- unsigned short defense_weight = 1024 - attack_weight;
- // at this point we have to be very careful with overflows, so we split the values like this
- unsigned long long attack_upper = attack_rating >> 32, attack_lower = attack_rating & 0xffffffffULL;
- unsigned long long defense_upper = defense_rating >> 32, defense_lower = defense_rating & 0xffffffffULL;
- attack_upper *= attack_weight;
- attack_lower *= attack_weight;
- defense_upper *= defense_weight;
- defense_lower *= defense_weight;
- unsigned long long rating = attack_upper + defense_upper, rating_lower = attack_lower + defense_lower;
- rating += (rating_lower >> 32) + 512; // don't lose the carry from the lower bits before we discard them, and add 0x200 to round to nearest in the next step
- return rating >> 10; // do away with all the shifts and return a rounded rating value
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement