Compare commits

...

11 Commits

Author SHA1 Message Date
cdemeyer-teachx
32b031f734 main.cpp 2025-08-21 09:50:16 +09:00
cdemeyer-teachx
212fdcd74f Merge commit '355903c1ffac1233dc65af206a74cd7e8387d9a3' 2025-08-21 09:32:05 +09:00
cdemeyer-teachx
355903c1ff Merge commit 'adf870871083d1341d0a8be61caf0d80842daf08' into Prompt/6-PokemonDataTable 2025-08-21 09:31:45 +09:00
cdemeyer-teachx
adf8708710 5d20e43f-cfcc-4489-bd25-9c8b412f3386 2025-08-20 16:00:00 +09:00
cdemeyer-teachx
58e3c1c734 prompt description 2025-08-20 15:54:17 +09:00
cdemeyer-teachx
aff99a507c code refactor 2025-08-20 13:02:04 +09:00
cdemeyer-teachx
cc78d15068 refactored data downloader 2025-08-20 08:30:07 +09:00
dd61d27d98 compilable for windows 2025-08-16 14:14:53 +09:00
cdemeyer-teachx
874dcfe450 Merge commit '269ad43957cf5f7cbbd6c8fa2b6038d81e4d483a' 2025-08-16 10:59:23 +09:00
cdemeyer-teachx
269ad43957 Merge commit '74b304de1e7d4c84e22b428814d2a61e2697749e' into Prompt/StatSystem 2025-08-16 10:59:08 +09:00
cdemeyer-teachx
74b304de1e 02ce465e-6601-4848-86cf-d86656f89730 2025-08-15 14:30:00 +00:00
68 changed files with 250024 additions and 8852 deletions

3
.gitignore vendored
View File

@@ -117,4 +117,5 @@ Thumbs.db
*.dmg
# Logs
*.log
*.log
.specstory/

View File

@@ -8,7 +8,7 @@ project(PokemonBattleSimulator
)
# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

218
POKEMON_TABLE_README.md Normal file
View File

@@ -0,0 +1,218 @@
# Pokemon Table Implementation
This document describes the high-performance Pokemon data table implementation for the Pokemon Battle Simulator.
## Overview
The Pokemon Table is a high-performance data structure that provides O(1) lookup access to all Pokemon species data. It loads Pokemon data from JSON files and stores them in memory for fast runtime access.
## Features
- **O(1) ID-based lookup**: Access any Pokemon by its ID in constant time
- **O(1) Name-based lookup**: Access any Pokemon by its name using a hash map
- **Automatic data loading**: Loads all Pokemon data from JSON files at startup
- **Memory efficient**: Uses contiguous memory storage for optimal cache performance
- **Type safety**: Strongly typed with comprehensive error handling
- **Validation**: Built-in data validation to ensure integrity
## Architecture
### Core Classes
#### `PokemonTable`
The main class that manages the Pokemon data table.
**Key Methods:**
- `loadFromDataDirectory()`: Loads Pokemon data from the standard data directory
- `loadFromFiles()`: Loads Pokemon data from specific JSON files
- `getPokemon(uint16_t id)`: O(1) lookup by Pokemon ID
- `getPokemonByName(std::string_view name)`: O(1) lookup by Pokemon name
- `hasPokemon(uint16_t id)`: Check if a Pokemon ID exists
- `size()`: Get the total number of loaded Pokemon
- `validate()`: Validate the integrity of loaded data
#### `PokemonSpecies`
Struct containing all the data for a single Pokemon species.
**Fields:**
- `id`: Pokemon ID (1-based)
- `name`: Pokemon name
- `base_stats`: Base stats (HP, Attack, Defense, SpAttack, SpDefense, Speed)
- `types`: Primary and secondary types
### Global Access
The implementation provides a global Pokemon table instance for convenient access:
```cpp
#include "core/pokemon_table.h"
// Initialize the global table (call once at startup)
bool success = PokEng::initializePokemonTable();
// Use the global table
const auto* bulbasaur = PokEng::g_pokemonTable->getPokemon(1);
const auto* charizard = PokEng::g_pokemonTable->getPokemonByName("charizard");
// Clean up (call at shutdown)
PokEng::shutdownPokemonTable();
```
## Performance
### Benchmarks
Based on the example program, the Pokemon table demonstrates excellent performance:
- **Initialization**: ~89ms to load 1025 Pokemon species
- **ID Lookups**: ~33,333 lookups per millisecond (100,000 lookups in 3ms)
- **Memory Usage**: Minimal memory footprint with contiguous storage
### Storage Strategy
The table uses a hybrid storage approach for optimal performance:
1. **Vector storage**: Pokemon species are stored in a `std::vector<PokemonSpecies>` indexed by ID
2. **Hash map**: Name-to-ID mapping using `std::unordered_map` for fast name lookups
3. **Index 0 unused**: Vector index 0 is unused, so Pokemon with ID 1 is at index 1
This approach provides:
- O(1) ID lookups via direct vector indexing
- O(1) average case name lookups via hash table
- Excellent cache locality for ID-based access patterns
## Usage Examples
### Basic Usage
```cpp
#include "core/pokemon_table.h"
int main() {
// Initialize the Pokemon table
if (!PokEng::initializePokemonTable()) {
std::cerr << "Failed to load Pokemon data!" << std::endl;
return 1;
}
// Look up Pokemon by ID
const auto* pikachu = PokEng::g_pokemonTable->getPokemon(25);
if (pikachu) {
std::cout << "Pikachu's speed: " << pikachu->base_stats.speed << std::endl;
std::cout << "Pikachu's type: " << PokEng::TypeUtils::typeToString(pikachu->types.getPrimary()) << std::endl;
}
// Look up Pokemon by name
const auto* charizard = PokEng::g_pokemonTable->getPokemonByName("charizard");
if (charizard) {
std::cout << "Charizard ID: " << charizard->id << std::endl;
}
// Clean up
PokEng::shutdownPokemonTable();
return 0;
}
```
### Advanced Usage
```cpp
// Check if Pokemon exists
if (PokEng::g_pokemonTable->hasPokemon(150)) {
const auto* mewtwo = PokEng::g_pokemonTable->getPokemon(150);
// Use mewtwo data...
}
// Iterate through all Pokemon
for (uint16_t id = 1; id <= PokEng::g_pokemonTable->getMaxId(); ++id) {
const auto* pokemon = PokEng::g_pokemonTable->getPokemon(id);
if (pokemon) {
// Process pokemon...
}
}
// Get all Pokemon at once (for bulk operations)
const auto& allPokemon = PokEng::g_pokemonTable->getAllPokemon();
for (const auto& pokemon : allPokemon) {
if (pokemon.id != 0) { // Skip empty entries
// Process pokemon...
}
}
```
## Data Loading
The Pokemon table automatically loads data from JSON files in the `data/pokemon/` directory:
- `generation-i.json` through `generation-ix.json`
- Each file contains Pokemon from a specific generation
- Data is validated during loading
### JSON Format
Each Pokemon entry in the JSON files has the following structure:
```json
{
"id": 1,
"name": "bulbasaur",
"height": 7,
"weight": 69,
"base_experience": 64,
"types": ["grass", "poison"],
"stats": {
"hp": 45,
"attack": 49,
"defense": 49,
"special-attack": 65,
"special-defense": 65,
"speed": 45
},
"abilities": [...],
"species": {...}
}
```
## Error Handling
The implementation includes comprehensive error handling:
- **File loading errors**: Graceful handling of missing or corrupted JSON files
- **JSON parsing errors**: Detailed error messages for malformed JSON
- **Data validation**: Built-in validation to ensure data integrity
- **Memory safety**: Proper resource management with RAII
## Testing
The implementation includes comprehensive unit tests covering:
- Data loading and initialization
- ID-based and name-based lookups
- Error handling for invalid inputs
- Performance validation
- Data integrity validation
Run tests with:
```bash
cd build
make test
```
## Integration
The Pokemon table is designed to integrate seamlessly with other components:
- **Pokemon creation**: Use table data to create Pokemon instances
- **Battle calculations**: Fast access to base stats and types
- **Type effectiveness**: Integration with type system for damage calculations
- **Stat calculations**: Base stats for battle stat computations
## Future Enhancements
Potential improvements for the Pokemon table:
1. **Lazy loading**: Load Pokemon data on-demand to reduce startup time
2. **Compressed storage**: Use compression to reduce memory footprint
3. **Multi-threading**: Parallel loading of Pokemon data
4. **Caching**: Implement LRU cache for frequently accessed Pokemon
5. **Serialization**: Save/load compiled Pokemon data for faster startup

2
Prompts/6-pokemonTable Normal file
View File

@@ -0,0 +1,2 @@
This repo is the start of a highly performant pokemon battle simulator.
I want you to implement a pokemon data table that contains all PokemonSpecies. So we can easily access any pokemon using it's ID during runtime.

View File

@@ -29,7 +29,7 @@ A high-performance C++ library for simulating Pokemon battles from Generation 1
## Build Requirements
- C++17 or later
- C++20 or later
- CMake 3.15+
- Python 3.8+ (for tooling)

View File

@@ -34,7 +34,7 @@ cmake/
- **Profile**: Special build for performance profiling
### Compiler Support
- **GCC 9+**: Primary compiler with full C++17 support
- **GCC 9+**: Primary compiler with full C++20 support
- **Clang 10+**: Alternative compiler with excellent diagnostics
- **MSVC 2019+**: Windows support with Visual Studio
- **Cross-compilation**: Support for different target architectures

View File

@@ -6,7 +6,11 @@ function(set_project_warnings)
add_compile_options(
/W4
/permissive-
/std:c++20 # Explicitly enable C++20 standard
$<$<BOOL:${WARNINGS_AS_ERRORS}>:/WX>
# Disable specific warnings that are too strict
/wd4244 # conversion from 'int' to 'char', possible loss of data
/wd4996 # 'fopen': This function or variable may be unsafe
)
else()
add_compile_options(

30688
data/all_moves.json Normal file

File diff suppressed because it is too large Load Diff

5777
data/moves/generation-i.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

12680
data/moves/generation-iii.json Normal file

File diff suppressed because it is too large Load Diff

16635
data/moves/generation-iv.json Normal file

File diff suppressed because it is too large Load Diff

30688
data/moves/generation-ix.json Normal file

File diff suppressed because it is too large Load Diff

19855
data/moves/generation-v.json Normal file

File diff suppressed because it is too large Load Diff

22025
data/moves/generation-vi.json Normal file

File diff suppressed because it is too large Load Diff

26260
data/moves/generation-vii.json Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,221 +0,0 @@
{
"2": {
"id": 2,
"name": "ivysaur",
"types": [
"grass",
"poison"
],
"base_stats": {
"hp": 60,
"attack": 62,
"defense": 63,
"special_attack": 80,
"special_defense": 80,
"speed": 60
},
"abilities": [
"overgrow",
"chlorophyll"
],
"moves": [
14,
15,
20,
22,
29,
33,
34,
36,
38,
45,
46,
70,
72,
73,
74,
75,
76,
77,
79,
80,
81,
92,
99,
102,
104,
111,
113,
115,
117,
133,
148,
156,
164,
173,
174,
182,
188,
189,
200,
202,
203,
204,
206,
207,
210,
213,
214,
216,
218,
219,
230,
235,
237,
241,
249,
263,
267,
270,
275,
282,
290,
311,
331,
345,
363,
388,
402,
412,
437,
438,
445,
447,
474,
491,
496,
497,
520,
526,
580,
590,
803,
851,
885
],
"weight": 130,
"height": 10,
"base_experience": 142
},
"1": {
"id": 1,
"name": "bulbasaur",
"types": [
"grass",
"poison"
],
"base_stats": {
"hp": 45,
"attack": 49,
"defense": 49,
"special_attack": 65,
"special_defense": 65,
"speed": 45
},
"abilities": [
"overgrow",
"chlorophyll"
],
"moves": [
13,
14,
15,
20,
22,
29,
33,
34,
36,
38,
45,
70,
72,
73,
74,
75,
76,
77,
79,
80,
81,
92,
99,
102,
104,
111,
113,
115,
117,
124,
130,
133,
148,
156,
164,
173,
174,
182,
188,
189,
200,
202,
203,
204,
206,
207,
210,
213,
214,
216,
218,
219,
230,
235,
237,
241,
249,
263,
267,
270,
275,
282,
290,
311,
320,
331,
345,
363,
388,
402,
412,
437,
438,
445,
447,
474,
491,
496,
497,
520,
526,
580,
590,
803,
851,
885
],
"weight": 69,
"height": 7,
"base_experience": 64
}
}

View File

@@ -1,412 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0
}
]

View File

@@ -1,494 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-i"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 0.0,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-i"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-i"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 1.0,
"generation": "generation-i"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-i"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-i"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 1.0,
"generation": "generation-i"
}
]

View File

@@ -1,650 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-ii"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ii"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ii"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-ii"
}
]

View File

@@ -1,650 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-iii"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iii"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iii"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-iii"
}
]

View File

@@ -1,650 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-iv"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-iv"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-iv"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-iv"
}
]

View File

@@ -1,722 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "bug",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "dragon",
"defending_type": "fairy",
"damage_factor": 0.0,
"generation": "generation-ix"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "dark",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fairy",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fairy",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fairy",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-ix"
},
{
"attacking_type": "fairy",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fairy",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-ix"
},
{
"attacking_type": "fairy",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-ix"
}
]

View File

@@ -1,662 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ghost",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-v"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "dark",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-v"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-v"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-v"
}
]

View File

@@ -1,722 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "bug",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "dragon",
"defending_type": "fairy",
"damage_factor": 0.0,
"generation": "generation-vi"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "dark",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fairy",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fairy",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fairy",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-vi"
},
{
"attacking_type": "fairy",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fairy",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vi"
},
{
"attacking_type": "fairy",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vi"
}
]

View File

@@ -1,722 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "bug",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "dragon",
"defending_type": "fairy",
"damage_factor": 0.0,
"generation": "generation-vii"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "dark",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fairy",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fairy",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fairy",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-vii"
},
{
"attacking_type": "fairy",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fairy",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-vii"
},
{
"attacking_type": "fairy",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-vii"
}
]

View File

@@ -1,722 +0,0 @@
[
{
"attacking_type": "normal",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "normal",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "normal",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fire",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "water",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "water",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "water",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "water",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "water",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "electric",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "electric",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "electric",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "electric",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "electric",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "electric",
"defending_type": "ground",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "water",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "grass",
"defending_type": "dragon",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "ground",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ice",
"defending_type": "ice",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "normal",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fighting",
"defending_type": "ghost",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "poison",
"defending_type": "steel",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "steel",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "electric",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "bug",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "grass",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ground",
"defending_type": "flying",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "flying",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "flying",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "flying",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "flying",
"defending_type": "rock",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "flying",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "flying",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "psychic",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "psychic",
"defending_type": "poison",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "psychic",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "psychic",
"defending_type": "psychic",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "psychic",
"defending_type": "dark",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "grass",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "flying",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "ghost",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "bug",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "flying",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "bug",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "fire",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "ground",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "rock",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ghost",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ghost",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "ghost",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "ghost",
"defending_type": "normal",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "dragon",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "dragon",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "dragon",
"defending_type": "fairy",
"damage_factor": 0.0,
"generation": "generation-viii"
},
{
"attacking_type": "dark",
"defending_type": "ghost",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "dark",
"defending_type": "psychic",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "dark",
"defending_type": "fighting",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "dark",
"defending_type": "dark",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "dark",
"defending_type": "fairy",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "rock",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "ice",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "fairy",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "water",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "steel",
"defending_type": "electric",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fairy",
"defending_type": "fighting",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fairy",
"defending_type": "dragon",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fairy",
"defending_type": "dark",
"damage_factor": 2.0,
"generation": "generation-viii"
},
{
"attacking_type": "fairy",
"defending_type": "poison",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fairy",
"defending_type": "steel",
"damage_factor": 0.5,
"generation": "generation-viii"
},
{
"attacking_type": "fairy",
"defending_type": "fire",
"damage_factor": 0.5,
"generation": "generation-viii"
}
]

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -0,0 +1,479 @@
{
"normal": {
"double_damage_from": [
"fighting"
],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [
"rock",
"steel"
],
"no_damage_from": [
"ghost"
],
"no_damage_to": [
"ghost"
]
},
"fighting": {
"double_damage_from": [
"flying",
"psychic",
"fairy"
],
"double_damage_to": [
"normal",
"rock",
"steel",
"ice",
"dark"
],
"half_damage_from": [
"rock",
"bug",
"dark"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"psychic",
"fairy"
],
"no_damage_from": [],
"no_damage_to": [
"ghost"
]
},
"flying": {
"double_damage_from": [
"rock",
"electric",
"ice"
],
"double_damage_to": [
"fighting",
"bug",
"grass"
],
"half_damage_from": [
"fighting",
"bug",
"grass"
],
"half_damage_to": [
"rock",
"steel",
"electric"
],
"no_damage_from": [
"ground"
],
"no_damage_to": []
},
"poison": {
"double_damage_from": [
"ground",
"psychic"
],
"double_damage_to": [
"grass",
"fairy"
],
"half_damage_from": [
"fighting",
"poison",
"bug",
"grass",
"fairy"
],
"half_damage_to": [
"poison",
"ground",
"rock",
"ghost"
],
"no_damage_from": [],
"no_damage_to": [
"steel"
]
},
"ground": {
"double_damage_from": [
"water",
"grass",
"ice"
],
"double_damage_to": [
"poison",
"rock",
"steel",
"fire",
"electric"
],
"half_damage_from": [
"poison",
"rock"
],
"half_damage_to": [
"bug",
"grass"
],
"no_damage_from": [
"electric"
],
"no_damage_to": [
"flying"
]
},
"rock": {
"double_damage_from": [
"fighting",
"ground",
"steel",
"water",
"grass"
],
"double_damage_to": [
"flying",
"bug",
"fire",
"ice"
],
"half_damage_from": [
"normal",
"flying",
"poison",
"fire"
],
"half_damage_to": [
"fighting",
"ground",
"steel"
],
"no_damage_from": [],
"no_damage_to": []
},
"bug": {
"double_damage_from": [
"flying",
"rock",
"fire"
],
"double_damage_to": [
"grass",
"psychic",
"dark"
],
"half_damage_from": [
"fighting",
"ground",
"grass"
],
"half_damage_to": [
"fighting",
"flying",
"poison",
"ghost",
"steel",
"fire",
"fairy"
],
"no_damage_from": [],
"no_damage_to": []
},
"ghost": {
"double_damage_from": [
"ghost",
"dark"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"poison",
"bug"
],
"half_damage_to": [
"dark"
],
"no_damage_from": [
"normal",
"fighting"
],
"no_damage_to": [
"normal"
]
},
"steel": {
"double_damage_from": [
"fighting",
"ground",
"fire"
],
"double_damage_to": [
"rock",
"ice",
"fairy"
],
"half_damage_from": [
"normal",
"flying",
"rock",
"bug",
"steel",
"grass",
"psychic",
"ice",
"dragon",
"fairy"
],
"half_damage_to": [
"steel",
"fire",
"water",
"electric"
],
"no_damage_from": [
"poison"
],
"no_damage_to": []
},
"fire": {
"double_damage_from": [
"ground",
"rock",
"water"
],
"double_damage_to": [
"bug",
"steel",
"grass",
"ice"
],
"half_damage_from": [
"bug",
"steel",
"fire",
"grass",
"ice",
"fairy"
],
"half_damage_to": [
"rock",
"fire",
"water",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"water": {
"double_damage_from": [
"grass",
"electric"
],
"double_damage_to": [
"ground",
"rock",
"fire"
],
"half_damage_from": [
"steel",
"fire",
"water",
"ice"
],
"half_damage_to": [
"water",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"grass": {
"double_damage_from": [
"flying",
"poison",
"bug",
"fire",
"ice"
],
"double_damage_to": [
"ground",
"rock",
"water"
],
"half_damage_from": [
"ground",
"water",
"grass",
"electric"
],
"half_damage_to": [
"flying",
"poison",
"bug",
"steel",
"fire",
"grass",
"dragon"
],
"no_damage_from": [],
"no_damage_to": []
},
"electric": {
"double_damage_from": [
"ground"
],
"double_damage_to": [
"flying",
"water"
],
"half_damage_from": [
"flying",
"steel",
"electric"
],
"half_damage_to": [
"grass",
"electric",
"dragon"
],
"no_damage_from": [],
"no_damage_to": [
"ground"
]
},
"psychic": {
"double_damage_from": [
"bug",
"ghost",
"dark"
],
"double_damage_to": [
"fighting",
"poison"
],
"half_damage_from": [
"fighting",
"psychic"
],
"half_damage_to": [
"steel",
"psychic"
],
"no_damage_from": [],
"no_damage_to": [
"dark"
]
},
"ice": {
"double_damage_from": [
"fighting",
"rock",
"steel",
"fire"
],
"double_damage_to": [
"flying",
"ground",
"grass",
"dragon"
],
"half_damage_from": [
"ice"
],
"half_damage_to": [
"steel",
"fire",
"water",
"ice"
],
"no_damage_from": [],
"no_damage_to": []
},
"dragon": {
"double_damage_from": [
"ice",
"dragon",
"fairy"
],
"double_damage_to": [
"dragon"
],
"half_damage_from": [
"fire",
"water",
"grass",
"electric"
],
"half_damage_to": [
"steel"
],
"no_damage_from": [],
"no_damage_to": [
"fairy"
]
},
"dark": {
"double_damage_from": [
"fighting",
"bug",
"fairy"
],
"double_damage_to": [
"ghost",
"psychic"
],
"half_damage_from": [
"ghost",
"dark"
],
"half_damage_to": [
"fighting",
"dark",
"fairy"
],
"no_damage_from": [
"psychic"
],
"no_damage_to": []
},
"fairy": {
"double_damage_from": [
"poison",
"steel"
],
"double_damage_to": [
"fighting",
"dragon",
"dark"
],
"half_damage_from": [
"fighting",
"bug",
"dark"
],
"half_damage_to": [
"poison",
"steel",
"fire"
],
"no_damage_from": [
"dragon"
],
"no_damage_to": []
},
"stellar": {
"double_damage_from": [],
"double_damage_to": [],
"half_damage_from": [],
"half_damage_to": [],
"no_damage_from": [],
"no_damage_to": []
}
}

View File

@@ -1,311 +0,0 @@
# Pokemon Type System Implementation
This document describes the high-performance Pokemon type system implementation for the Pokemon Battle Simulator.
## Overview
The type system provides:
- **High-performance type effectiveness calculations** using integer arithmetic only
- **Multi-generation support** without runtime generation checks
- **Dual-type Pokemon support** with proper damage multiplier calculations
- **JSON-based type chart loading** from the provided data files
- **Comprehensive testing and benchmarking** for performance validation
## Key Features
### 1. Performance Optimizations
- **Integer-only arithmetic**: Uses integer multipliers (0, 1, 2, 4, 8, 16) representing (0x, 0.25x, 0.5x, 1x, 2x, 4x) damage
- **Compile-time generation selection**: Template-based generation support eliminates runtime checks
- **Cache-friendly type chart storage**: 2D array layout optimized for CPU cache performance
- **Minimal memory allocations**: Static storage for type charts loaded at startup
### 2. Type System Architecture
#### Core Components
- **`Type` enum**: All 19 Pokemon types (Generation 1-9)
- **`TypeMultiplier` enum**: Integer damage multipliers
- **`Generation` enum**: Pokemon game generations
- **`PokemonTypes` class**: Represents single/dual-type Pokemon
- **`TypeUtils` class**: Core type system functionality
- **`TypeChartTraits` template**: Generation-specific type chart access
#### Type Multipliers
```cpp
enum class TypeMultiplier : uint8_t {
ZERO = 0, // 0x damage (immune)
QUARTER = 1, // 0.25x damage
HALF = 2, // 0.5x damage
NEUTRAL = 4, // 1x damage (neutral)
DOUBLE = 8, // 2x damage
QUADRUPLE = 16 // 4x damage
};
```
### 3. Usage Examples
#### Basic Type Effectiveness
```cpp
using namespace PokEng;
// Calculate damage with type effectiveness
uint32_t damage = calculateTypeDamage<Generation::I>(
100, // Base damage
Type::WATER, // Attack type
Type::FIRE // Defender type
);
// Result: 200 (Water is super effective against Fire)
```
#### Dual-Type Pokemon
```cpp
// Electric attack on Water/Flying Pokemon
uint32_t damage = calculateTypeDamage<Generation::I>(
100, // Base damage
Type::ELECTRIC, // Attack type
Type::WATER, // Primary defender type
Type::FLYING // Secondary defender type
);
// Result: 400 (Electric is super effective against both types)
```
#### Pokemon with Types
```cpp
// Create Pokemon with types
Pokemon charizard("Charizard", 150, Type::FIRE, Type::FLYING);
Pokemon blastoise("Blastoise", 150, Type::WATER);
// Calculate damage using Pokemon methods
uint32_t damage = charizard.calculateDamageTaken<Generation::I>(
100, // Base damage
Type::WATER // Attack type
);
// Result: 200 (Water is super effective against Fire)
```
### 4. Generation Support
The system supports all Pokemon generations through compile-time templates:
```cpp
// Generation 1 type effectiveness
auto gen1Damage = calculateTypeDamage<Generation::I>(100, Type::FIRE, Type::WATER);
// Generation 8 type effectiveness
auto gen8Damage = calculateTypeDamage<Generation::VIII>(100, Type::FIRE, Type::WATER);
```
Each generation has its own type chart loaded from the corresponding JSON file.
### 5. Type Chart Loading
Type charts are loaded from JSON files at program startup:
- `data/type_effectiveness_generation-i.json` → Generation 1
- `data/type_effectiveness_generation-ii.json` → Generation 2
- ... and so on through Generation 9
The loading process:
1. Parses JSON using RapidJSON
2. Converts float multipliers to integer TypeMultiplier values
3. Stores in optimized 2D array format
4. Provides O(1) lookup performance
## Performance Characteristics
### Benchmarks
The implementation includes comprehensive benchmarks:
```bash
# Run type system benchmarks
./build/benchmarks/benchmarks
# Run specific benchmark
./build/benchmarks/benchmarks --benchmark_filter=TypeSystemBenchmark
```
Key benchmark results (example):
- **Type effectiveness lookup**: ~1-2 nanoseconds
- **Damage multiplier calculation**: ~2-3 nanoseconds
- **Full damage calculation**: ~3-5 nanoseconds
- **Batch processing**: Sub-microsecond for realistic scenarios
### Memory Layout
- Type charts: ~3KB per generation (19x19 types)
- Total memory: ~27KB for all 9 generations
- Cache-friendly access pattern: Row-major order for optimal CPU cache usage
## Testing
### Unit Tests
Comprehensive unit test coverage:
```bash
# Run type system tests
./build/tests/unit/core/test_types
# Run all tests
./build/tests/test_all.sh
```
Test categories:
- **Type string conversion**: Valid/invalid conversions
- **Type effectiveness**: Known type matchups
- **Damage calculations**: Single/dual-type scenarios
- **Edge cases**: Immunity, invalid inputs
- **Generation differences**: Cross-generation behavior
- **Performance**: Speed validation
### Example Output
```cpp
// Test: Water attack on Fire type
uint32_t damage = calculateTypeDamage<Generation::I>(100, Type::WATER, Type::FIRE);
ASSERT_EQ(damage, 200); // Water is super effective (2x) against Fire
// Test: Dual-type Electric attack on Water/Flying
uint32_t dualDamage = calculateTypeDamage<Generation::I>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
ASSERT_EQ(dualDamage, 400); // Electric is super effective (2x) against both types = 4x total
```
## API Reference
### Core Functions
#### `calculateTypeDamage`
```cpp
template <Generation Gen = Generation::I>
uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, const PokemonTypes& defenderTypes);
template <Generation Gen = Generation::I>
uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType);
template <Generation Gen = Generation::I>
uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType1, Type defenderType2);
```
#### `TypeUtils` Methods
```cpp
static std::optional<Type> stringToType(std::string_view typeStr);
static std::string_view typeToString(Type type);
static TypeMultiplier getTypeEffectiveness(Type attackType, Type defendType);
static uint32_t calculateDamageMultiplier(Type attackType, const PokemonTypes& defenderTypes);
```
### Type Enums
#### `Type`
```cpp
enum class Type : uint8_t {
NONE = 0, NORMAL, FIRE, WATER, ELECTRIC, GRASS, ICE, FIGHTING,
POISON, GROUND, FLYING, PSYCHIC, BUG, ROCK, GHOST, DRAGON,
DARK, STEEL, FAIRY, TYPE_COUNT
};
```
#### `Generation`
```cpp
enum class Generation : uint8_t {
I = 1, II = 2, III = 3, IV = 4,
V = 5, VI = 6, VII = 7, VIII = 8,
IX = 9
};
```
## Building and Running
### Dependencies
- C++17 compatible compiler
- RapidJSON (header-only, included in `thirdParty/rapidjson`)
- CMake 3.15+
- Google Test (for unit tests)
- Google Benchmark (for performance tests)
### Build Commands
```bash
# Configure
cmake -B build -S . -DCMAKE_BUILD_TYPE=Release
# Build
cmake --build build --config Release
# Run tests
cd build && ctest --output-on-failure
# Run benchmarks
./benchmarks/benchmarks
# Run example
./examples/type_system_example
```
### Integration
To use the type system in your code:
```cpp
#include "types.h"
// Use the high-level API
uint32_t damage = PokEng::calculateTypeDamage(
100, Type::FIRE, Type::GRASS
);
```
## Design Decisions
### Integer-Only Arithmetic
- **Rationale**: Floating-point operations are slower and introduce precision issues
- **Solution**: Use integer multipliers with division by 4 for final damage calculation
- **Benefit**: 2-3x performance improvement over float-based calculations
### Template-Based Generations
- **Rationale**: Runtime generation checks would add overhead
- **Solution**: Compile-time generation selection via templates
- **Benefit**: Zero runtime overhead for generation selection
### Static Type Charts
- **Rationale**: Type effectiveness rarely changes during program execution
- **Solution**: Load once at startup, store in static arrays
- **Benefit**: Optimal cache performance for repeated lookups
## Future Enhancements
Potential improvements:
1. **SIMD optimizations** for batch damage calculations
2. **Memory-mapped file loading** for reduced startup time
3. **Type combination caching** for frequently used type pairs
4. **Custom type chart support** for ROM hacks/modifications
5. **Advanced effectiveness rules** (e.g., Freeze Dry, Flying Press)
## Contributing
When extending the type system:
1. Add new types to the `Type` enum
2. Update string conversion mappings
3. Add new JSON data files for type effectiveness
4. Update template instantiations
5. Add comprehensive unit tests
6. Add performance benchmarks
7. Update documentation
## License
This implementation is part of the Pokemon Battle Simulator project. See LICENSE file for details.

View File

@@ -0,0 +1,108 @@
#include "core/pokemon_table.h"
#include <iostream>
#include <iomanip>
#include <chrono>
using namespace PokEng;
int main() {
std::cout << "Pokemon Table Example" << std::endl;
std::cout << "====================" << std::endl;
// Initialize the global Pokemon table
auto start = std::chrono::high_resolution_clock::now();
if (!initializePokemonTable()) {
std::cerr << "Failed to initialize Pokemon table!" << std::endl;
return 1;
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Pokemon table initialized in " << duration.count() << "ms" << std::endl;
std::cout << "Total Pokemon loaded: " << g_pokemonTable->size() << std::endl;
std::cout << "Max Pokemon ID: " << g_pokemonTable->getMaxId() << std::endl;
std::cout << std::endl;
// Demonstrate fast ID-based lookup
std::cout << "Fast ID-based lookups:" << std::endl;
std::cout << "--------------------" << std::endl;
const uint16_t testIds[] = {1, 25, 150, 493, 807, 905}; // Bulbasaur, Pikachu, Mewtwo, Arceus, Zeraora, Enamorus
for (uint16_t id : testIds) {
const auto* pokemon = g_pokemonTable->getPokemon(id);
if (pokemon) {
std::cout << "#" << std::setw(3) << std::setfill('0') << pokemon->id << " "
<< std::setw(15) << std::left << pokemon->name << " | "
<< "HP: " << std::setw(3) << static_cast<int>(pokemon->base_stats.hp) << " | "
<< "Atk: " << std::setw(3) << static_cast<int>(pokemon->base_stats.attack) << " | "
<< "Def: " << std::setw(3) << static_cast<int>(pokemon->base_stats.defense) << " | "
<< "SpA: " << std::setw(3) << static_cast<int>(pokemon->base_stats.sp_attack) << " | "
<< "SpD: " << std::setw(3) << static_cast<int>(pokemon->base_stats.sp_defense) << " | "
<< "Spe: " << std::setw(3) << static_cast<int>(pokemon->base_stats.speed) << " | "
<< "Type: " << TypeUtils::typeToString(pokemon->types.getPrimary());
if (pokemon->types.hasSecondary()) {
std::cout << "/" << TypeUtils::typeToString(pokemon->types.getSecondary());
}
std::cout << std::endl;
}
}
std::cout << std::endl;
// Demonstrate name-based lookup
std::cout << "Name-based lookups:" << std::endl;
std::cout << "------------------" << std::endl;
const std::string testNames[] = {"charizard", "gengar", "snorlax", "dragonite", "mew"};
for (const auto& name : testNames) {
const auto* pokemon = g_pokemonTable->getPokemonByName(name);
if (pokemon) {
std::cout << "#" << std::setw(3) << std::setfill('0') << pokemon->id << " "
<< std::setw(12) << std::left << pokemon->name << " | "
<< "Total: " << std::setw(3) << (pokemon->base_stats.hp +
pokemon->base_stats.attack +
pokemon->base_stats.defense +
pokemon->base_stats.sp_attack +
pokemon->base_stats.sp_defense +
pokemon->base_stats.speed)
<< std::endl;
} else {
std::cout << "Pokemon '" << name << "' not found" << std::endl;
}
}
std::cout << std::endl;
// Performance test for ID lookups
std::cout << "Performance test (100,000 ID lookups):" << std::endl;
std::cout << "--------------------------------------" << std::endl;
start = std::chrono::high_resolution_clock::now();
volatile size_t checksum = 0; // Prevent optimization
for (int i = 0; i < 100000; ++i) {
uint16_t randomId = (i % g_pokemonTable->getMaxId()) + 1;
const auto* pokemon = g_pokemonTable->getPokemon(randomId);
if (pokemon) {
checksum += pokemon->base_stats.hp;
}
}
end = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Time: " << duration.count() << "ms (" << (100000.0 / duration.count()) << " lookups/ms)" << std::endl;
std::cout << "Checksum: " << checksum << std::endl;
// Cleanup
shutdownPokemonTable();
std::cout << std::endl;
std::cout << "Example completed successfully!" << std::endl;
return 0;
}

View File

@@ -1,117 +0,0 @@
// Type System Example
// Demonstrates how to use the high-performance Pokemon type system
#include "pokemon_battle_sim.h"
#include <iostream>
#include <iomanip>
using namespace PokEng;
int main() {
std::cout << "=== Pokemon Type System Example ===\n\n";
// Example 1: Basic type effectiveness lookup
std::cout << "1. Basic Type Effectiveness Examples:\n";
std::cout << "-----------------------------------\n";
// Water attack on Fire type (super effective)
uint32_t damage1 = calculateTypeDamage<Generation::I>(100, Type::WATER, Type::FIRE);
std::cout << "Water attack on Fire Pokemon: " << damage1 << " damage (expected: 200)\n";
// Fire attack on Water type (not very effective)
uint32_t damage2 = calculateTypeDamage<Generation::I>(100, Type::FIRE, Type::WATER);
std::cout << "Fire attack on Water Pokemon: " << damage2 << " damage (expected: 50)\n";
// Normal attack on Ghost type (immune)
uint32_t damage3 = calculateTypeDamage<Generation::I>(100, Type::NORMAL, Type::GHOST);
std::cout << "Normal attack on Ghost Pokemon: " << damage3 << " damage (expected: 0)\n";
std::cout << "\n";
// Example 2: Dual-type Pokemon
std::cout << "2. Dual-Type Pokemon Examples:\n";
std::cout << "-----------------------------\n";
// Electric attack on Water/Flying (super effective against both)
uint32_t damage4 = calculateTypeDamage<Generation::I>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
std::cout << "Electric attack on Water/Flying Pokemon: " << damage4 << " damage (4x effective)\n";
// Grass attack on Water/Flying (mixed effectiveness)
uint32_t damage5 = calculateTypeDamage<Generation::I>(100, Type::GRASS, Type::WATER, Type::FLYING);
std::cout << "Grass attack on Water/Flying Pokemon: " << damage5 << " damage (neutral effectiveness)\n";
std::cout << "\n";
// Example 3: Pokemon with types
std::cout << "3. Pokemon with Type Support:\n";
std::cout << "-----------------------------\n";
// Create some Pokemon with different types
Pokemon charizard(6, 150, Type::FIRE, Type::FLYING);
Pokemon blastoise(9, 150, Type::WATER);
Pokemon venusaur(3, 150, Type::GRASS, Type::POISON);
std::cout << charizard.getId() << " (Fire/Flying) has "
<< TypeUtils::typeToString(charizard.getTypes().getPrimary()) << "/"
<< TypeUtils::typeToString(charizard.getTypes().getSecondary()) << " types\n";
std::cout << blastoise.getId() << " (Water) has "
<< TypeUtils::typeToString(blastoise.getTypes().getPrimary()) << " type\n";
std::cout << venusaur.getId() << " (Grass/Poison) has "
<< TypeUtils::typeToString(venusaur.getTypes().getPrimary()) << "/"
<< TypeUtils::typeToString(venusaur.getTypes().getSecondary()) << " types\n";
std::cout << "\n";
// Example 4: Damage calculation using Pokemon methods
std::cout << "4. Damage Calculations Using Pokemon Methods:\n";
std::cout << "--------------------------------------------\n";
uint32_t fireDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::FIRE);
std::cout << "Charizard takes " << fireDamage << " damage from Fire attack (expected: 50)\n";
uint32_t waterDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::WATER);
std::cout << "Charizard takes " << waterDamage << " damage from Water attack (expected: 200)\n";
uint32_t electricDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::ELECTRIC);
std::cout << "Charizard takes " << electricDamage << " damage from Electric attack (expected: 200)\n";
uint32_t groundDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::GROUND);
std::cout << "Charizard takes " << groundDamage << " damage from Ground attack (expected: 0 - immune)\n";
std::cout << "\n";
// Example 5: Different generations
std::cout << "5. Generation Differences:\n";
std::cout << "-------------------------\n";
// Steel type was introduced in Gen 2, so Steel moves don't exist in Gen 1
uint32_t gen1Damage = calculateTypeDamage<Generation::I>(100, Type::NORMAL, Type::STEEL);
uint32_t gen8Damage = calculateTypeDamage<Generation::VIII>(100, Type::NORMAL, Type::STEEL);
std::cout << "Normal attack on Steel in Generation 1: " << gen1Damage << " damage\n";
std::cout << "Normal attack on Steel in Generation 8: " << gen8Damage << " damage\n";
std::cout << "(Note: Steel type behavior may differ across generations)\n";
std::cout << "\n";
// Example 6: Type string conversion
std::cout << "6. Type String Conversion:\n";
std::cout << "-------------------------\n";
std::vector<Type> typesToTest = {Type::FIRE, Type::WATER, Type::GRASS, Type::ELECTRIC, Type::FAIRY};
for (Type type : typesToTest) {
std::string_view typeName = TypeUtils::typeToString(type);
auto convertedBack = TypeUtils::stringToType(typeName);
std::cout << "Type: " << typeName << " -> "
<< (convertedBack ? TypeUtils::typeToString(*convertedBack) : "ERROR")
<< " (conversion " << (convertedBack ? "successful" : "failed") << ")\n";
}
std::cout << "\n=== Example Complete ===\n";
return 0;
}

View File

@@ -1,26 +0,0 @@
#ifndef BATTLE_H
#define BATTLE_H
#include "pokemon.h"
namespace PokEng {
// High-level type system functions for easy use
template <Generation Gen = Generation::I>
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, const PokemonTypes& defenderTypes) {
return calculateDamage<Gen>(baseDamage, attackType, defenderTypes);
}
template <Generation Gen = Generation::I>
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType) {
return calculateDamage<Gen>(baseDamage, attackType, PokemonTypes(defenderType));
}
template <Generation Gen = Generation::I>
inline uint32_t calculateTypeDamage(uint32_t baseDamage, Type attackType, Type defenderType1, Type defenderType2) {
return calculateDamage<Gen>(baseDamage, attackType, PokemonTypes(defenderType1, defenderType2));
}
} // namespace PokEng
#endif

View File

@@ -18,6 +18,89 @@ VIII = 8,
IX = 9
};
// Stat indices for nature calculations
enum class StatIndex : uint8_t {
HP = 0,
ATTACK = 1,
DEFENSE = 2,
SP_ATTACK = 3,
SP_DEFENSE = 4,
SPEED = 5
};
// Pokemon Nature - encoded as 8 bits: upper 4 bits = positive stat, lower 4 bits = negative stat
// Stat encoding: 0=HP/None, 1=Attack, 2=Defense, 3=SpAttack, 4=SpDefense, 5=Speed
struct Nature {
private:
uint8_t m_encoded; // Upper 4 bits: positive stat, Lower 4 bits: negative stat
public:
// Constructor from encoded value
constexpr explicit Nature(uint8_t encoded = 0) : m_encoded(encoded) {}
// Constructor from positive and negative stats
constexpr Nature(StatIndex positive, StatIndex negative)
: m_encoded((static_cast<uint8_t>(positive) << 4) | static_cast<uint8_t>(negative)) {}
// Get the stat that is increased by this nature
constexpr StatIndex getPositiveStat() const {
return static_cast<StatIndex>((m_encoded >> 4) & 0xF);
}
// Get the stat that is decreased by this nature
constexpr StatIndex getNegativeStat() const {
return static_cast<StatIndex>(m_encoded & 0xF);
}
// Check if nature is neutral (same positive and negative stat)
constexpr bool isNeutral() const {
return getPositiveStat() == getNegativeStat();
}
constexpr uint8_t getMultiplier10(StatIndex stat) const {
return static_cast<uint8_t>(10u + (getPositiveStat() == stat) - (getNegativeStat() == stat));
}
// Get encoded value
constexpr uint8_t getEncoded() const { return m_encoded; }
// Comparison operators
constexpr bool operator==(const Nature& other) const { return m_encoded == other.m_encoded; }
constexpr bool operator!=(const Nature& other) const { return m_encoded != other.m_encoded; }
// Predefined nature constants
static constexpr Nature HARDY() { return Nature(StatIndex::ATTACK, StatIndex::ATTACK); }
static constexpr Nature DOCILE() { return Nature(StatIndex::DEFENSE, StatIndex::DEFENSE); }
static constexpr Nature BASHFUL() { return Nature(StatIndex::SP_ATTACK, StatIndex::SP_ATTACK); }
static constexpr Nature QUIRKY() { return Nature(StatIndex::SP_DEFENSE, StatIndex::SP_DEFENSE); }
static constexpr Nature SERIOUS() { return Nature(StatIndex::SPEED, StatIndex::SPEED); }
static constexpr Nature LONELY() { return Nature(StatIndex::ATTACK, StatIndex::DEFENSE); }
static constexpr Nature ADAMANT() { return Nature(StatIndex::ATTACK, StatIndex::SP_ATTACK); }
static constexpr Nature NAUGHTY() { return Nature(StatIndex::ATTACK, StatIndex::SP_DEFENSE); }
static constexpr Nature BRAVE() { return Nature(StatIndex::ATTACK, StatIndex::SPEED); }
static constexpr Nature BOLD() { return Nature(StatIndex::DEFENSE, StatIndex::ATTACK); }
static constexpr Nature IMPISH() { return Nature(StatIndex::DEFENSE, StatIndex::SP_ATTACK); }
static constexpr Nature LAX() { return Nature(StatIndex::DEFENSE, StatIndex::SP_DEFENSE); }
static constexpr Nature RELAXED() { return Nature(StatIndex::DEFENSE, StatIndex::SPEED); }
static constexpr Nature MODEST() { return Nature(StatIndex::SP_ATTACK, StatIndex::ATTACK); }
static constexpr Nature MILD() { return Nature(StatIndex::SP_ATTACK, StatIndex::DEFENSE); }
static constexpr Nature RASH() { return Nature(StatIndex::SP_ATTACK, StatIndex::SP_DEFENSE); }
static constexpr Nature QUIET() { return Nature(StatIndex::SP_ATTACK, StatIndex::SPEED); }
static constexpr Nature CALM() { return Nature(StatIndex::SP_DEFENSE, StatIndex::ATTACK); }
static constexpr Nature GENTLE() { return Nature(StatIndex::SP_DEFENSE, StatIndex::DEFENSE); }
static constexpr Nature CAREFUL() { return Nature(StatIndex::SP_DEFENSE, StatIndex::SP_ATTACK); }
static constexpr Nature SASSY() { return Nature(StatIndex::SP_DEFENSE, StatIndex::SPEED); }
static constexpr Nature TIMID() { return Nature(StatIndex::SPEED, StatIndex::ATTACK); }
static constexpr Nature HASTY() { return Nature(StatIndex::SPEED, StatIndex::DEFENSE); }
static constexpr Nature JOLLY() { return Nature(StatIndex::SPEED, StatIndex::SP_ATTACK); }
static constexpr Nature NAIVE() { return Nature(StatIndex::SPEED, StatIndex::SP_DEFENSE); }
};
} // namespace PokEng

View File

@@ -2,37 +2,99 @@
#define POKEMON_H
#include "config.h"
#include "stats.h"
#include "types.h"
#include <string>
namespace PokEng {
// Pokemon species data structure
struct PokemonSpecies {
PokemonSpecies() = default;
class Pokemon {
public:
Pokemon() = default;
~Pokemon() = default;
Pokemon(uint16_t id) : m_id(id) {}
Pokemon(uint16_t id, uint16_t health) : m_id(id), m_health(health) {}
Pokemon(uint16_t id, uint16_t health, Type primaryType) : m_id(id), m_health(health), m_types(primaryType) {}
Pokemon(uint16_t id, uint16_t health, Type primaryType, Type secondaryType) : m_id(id), m_health(health), m_types(primaryType, secondaryType) {}
std::string name;
uint16_t id;
BaseStats base_stats;
PokemonTypes types;
};
// Pokemon Archetype - contains information on how a pokemon will be instantiated
class PokemonArchetype {
public:
PokemonArchetype() = default;
PokemonArchetype(uint16_t species_id, uint8_t level = 50,
Nature nature = Nature::HARDY(),
const IndividualValues& ivs = IndividualValues(),
const EffortValues& evs = EffortValues(),
uint32_t exp = 0)
: m_species_id(species_id), m_level(level), m_nature(nature),
m_ivs(ivs), m_evs(evs), m_exp(exp) {}
// Getters
uint16_t getId() const { return m_id; }
uint16_t getHealth() const { return m_health; }
PokemonTypes getTypes() const { return m_types; }
uint16_t getSpeciesId() const { return m_species_id; }
uint8_t getLevel() const { return m_level; }
Nature getNature() const { return m_nature; }
const IndividualValues& getIVs() const { return m_ivs; }
const EffortValues& getEVs() const { return m_evs; }
uint32_t getExp() const { return m_exp; }
// Setters
void setSpeciesId(uint16_t species_id) { m_species_id = species_id; }
void setLevel(uint8_t level) { m_level = (level > 100) ? 100 : level; }
void setNature(Nature nature) { m_nature = nature; }
void setIVs(const IndividualValues& ivs) { m_ivs = ivs; }
void setEVs(const EffortValues& evs) { if (evs.isValid()) m_evs = evs; }
void setExp(uint32_t exp) { m_exp = exp; }
// Calculate battle stats for different generations
template<Generation Gen>
BattleStats calculateBattleStats() const;
private:
uint16_t m_species_id = 0;
uint8_t m_level = 50;
Nature m_nature = Nature::HARDY();
IndividualValues m_ivs;
EffortValues m_evs;
uint32_t m_exp = 0; // For Gen I & II stat calculations
};
// Pokemon Instance - only contains data needed for battle
class PokemonInstance {
public:
PokemonInstance() = default;
PokemonInstance(uint16_t species_id, const BattleStats& stats,
const PokemonTypes& types, uint8_t friendship = 0)
: m_species_id(species_id), m_battle_stats(stats), m_types(types),
m_current_hp(stats.hp), m_friendship(friendship) {}
// Create from archetype
template<Generation Gen>
static PokemonInstance fromArchetype(const PokemonArchetype& archetype, uint8_t friendship = 0);
// Getters
uint16_t getSpeciesId() const { return m_species_id; }
uint16_t getCurrentHP() const { return m_current_hp; }
uint16_t getMaxHP() const { return m_battle_stats.hp; }
const BattleStats& getBattleStats() const { return m_battle_stats; }
const PokemonTypes& getTypes() const { return m_types; }
Type getPrimaryType() const { return m_types.getPrimary(); }
Type getSecondaryType() const { return m_types.getSecondary(); }
uint8_t getFriendship() const { return m_friendship; }
// Battle stat getters
uint16_t getAttack() const { return m_battle_stats.attack; }
uint16_t getDefense() const { return m_battle_stats.defense; }
uint16_t getSpAttack() const { return m_battle_stats.sp_attack; }
uint16_t getSpDefense() const { return m_battle_stats.sp_defense; }
uint16_t getSpeed() const { return m_battle_stats.speed; }
// Setters
void setHealth(uint16_t health) { m_health = health; }
void setTypes(Type primary) { m_types.setPrimary(primary); m_types.setSecondary(Type::NONE); }
void setTypes(Type primary, Type secondary) { m_types.setPrimary(primary); m_types.setSecondary(secondary); }
void SetPokemonTypes(PokemonTypes types) { m_types = types; }
public:
void setCurrentHP(uint16_t hp) {
m_current_hp = (hp > m_battle_stats.hp) ? m_battle_stats.hp : hp;
}
void setFriendship(uint8_t friendship) { m_friendship = friendship; }
// Type-based operations
template <Generation Gen = Generation::I>
uint32_t calculateDamageTaken(uint32_t baseDamage, Type attackType) const {
@@ -40,11 +102,13 @@ public:
}
private:
uint16_t m_id;
uint16_t m_health;
uint16_t m_species_id = 0;
BattleStats m_battle_stats;
PokemonTypes m_types;
uint16_t m_current_hp = 0;
uint8_t m_friendship = 0;
};
} // namespace PokEng
#endif
#endif // POKEMON_H

View File

@@ -0,0 +1,209 @@
#ifndef POKEMON_TABLE_H
#define POKEMON_TABLE_H
#include "pokemon.h"
#include <vector>
#include <unordered_map>
#include <memory>
#include <string>
#include <string_view>
#include <optional>
namespace PokEng {
// Forward declaration
struct PokemonSpecies;
/**
* @brief A high-performance Pokemon data table that provides O(1) lookup by ID
*
* This class loads all Pokemon species data from JSON files and stores them
* in a way that allows for extremely fast runtime access by Pokemon ID.
* The table is designed to be loaded once at startup and then used throughout
* the application's lifetime.
*/
class PokemonTable {
public:
/**
* @brief Default constructor
*
* Creates an empty Pokemon table. Use loadFromDataDirectory() or
* loadFromFiles() to populate the table with data.
*/
PokemonTable() = default;
/**
* @brief Destructor
*/
~PokemonTable() = default;
// Delete copy operations to prevent accidental copies
PokemonTable(const PokemonTable&) = delete;
PokemonTable& operator=(const PokemonTable&) = delete;
// Allow move operations
PokemonTable(PokemonTable&&) = default;
PokemonTable& operator=(PokemonTable&&) = default;
/**
* @brief Load Pokemon data from the standard data directory
*
* This method loads all Pokemon data from the JSON files in the
* data/pokemon/ directory, parsing all generations.
*
* @return true if loading was successful, false otherwise
*/
bool loadFromDataDirectory();
/**
* @brief Load Pokemon data from specific JSON files
*
* @param filePaths Vector of paths to JSON files containing Pokemon data
* @return true if loading was successful, false otherwise
*/
bool loadFromFiles(const std::vector<std::string>& filePaths);
/**
* @brief Get a Pokemon species by its ID
*
* This is the primary lookup method and provides O(1) access time.
*
* @param id The Pokemon ID (1-based, e.g., 1 = Bulbasaur)
* @return Pointer to the PokemonSpecies if found, nullptr otherwise
*/
const PokemonSpecies* getPokemon(uint16_t id) const;
/**
* @brief Get a Pokemon species by its name
*
* This method provides O(1) access time using an internal hash map.
*
* @param name The Pokemon name (case-sensitive)
* @return Pointer to the PokemonSpecies if found, nullptr otherwise
*/
const PokemonSpecies* getPokemonByName(std::string_view name) const;
/**
* @brief Check if a Pokemon ID exists in the table
*
* @param id The Pokemon ID to check
* @return true if the Pokemon exists, false otherwise
*/
bool hasPokemon(uint16_t id) const;
/**
* @brief Get the total number of Pokemon species in the table
*
* @return The number of Pokemon species loaded
*/
size_t size() const;
/**
* @brief Check if the table is empty
*
* @return true if no Pokemon data has been loaded, false otherwise
*/
bool empty() const;
/**
* @brief Get the highest Pokemon ID in the table
*
* @return The maximum Pokemon ID, or 0 if the table is empty
*/
uint16_t getMaxId() const;
/**
* @brief Clear all data from the table
*/
void clear();
/**
* @brief Get all Pokemon species (for iteration)
*
* @return A const reference to the internal vector of Pokemon species
*/
const std::vector<PokemonSpecies>& getAllPokemon() const;
/**
* @brief Validate that the table contains valid data
*
* This method performs basic validation checks on the loaded data.
*
* @return true if the data appears valid, false otherwise
*/
bool validate() const;
private:
/**
* @brief Parse a single Pokemon JSON file
*
* @param filePath Path to the JSON file to parse
* @return true if parsing was successful, false otherwise
*/
bool parsePokemonFile(const std::string& filePath);
/**
* @brief Parse a single Pokemon object from JSON
*
* @param pokemonJson The JSON value representing a Pokemon
* @return The parsed PokemonSpecies object
*/
PokemonSpecies parsePokemonJson(const void* pokemonJson);
/**
* @brief Parse base stats from JSON
*
* @param statsJson The JSON value containing the stats object
* @return The parsed BaseStats object
*/
BaseStats parseBaseStats(const void* statsJson);
/**
* @brief Parse Pokemon types from JSON
*
* @param typesJson The JSON array containing the types
* @return The parsed PokemonTypes object
*/
PokemonTypes parseTypes(const void* typesJson);
private:
// Storage for Pokemon species - indexed by ID (1-based)
// Index 0 is unused, index 1 = Bulbasaur, etc.
std::vector<PokemonSpecies> m_pokemonSpecies;
// Hash map for name-based lookups
std::unordered_map<std::string, uint16_t> m_nameToIdMap;
// Track the maximum ID for validation
uint16_t m_maxId = 0;
};
/**
* @brief Global Pokemon table instance
*
* This provides a convenient global access point to the Pokemon data.
* The table should be initialized once at application startup.
*/
extern std::unique_ptr<PokemonTable> g_pokemonTable;
/**
* @brief Initialize the global Pokemon table
*
* This function should be called once at application startup to load
* all Pokemon data. It loads from the standard data directory.
*
* @return true if initialization was successful, false otherwise
*/
bool initializePokemonTable();
/**
* @brief Shutdown the global Pokemon table
*
* This function should be called at application shutdown to clean up
* the global Pokemon table resources.
*/
void shutdownPokemonTable();
} // namespace PokEng
#endif // POKEMON_TABLE_H

221
include/core/stats.h Normal file
View File

@@ -0,0 +1,221 @@
#ifndef STATS_H
#define STATS_H
#include "config.h"
#include <cstdint>
#include <array>
#include <cmath>
namespace PokEng {
// Forward declaration
class PokemonInfo;
// Base stats structure for a Pokemon species
struct BaseStats {
uint8_t hp;
uint8_t attack;
uint8_t defense;
uint8_t sp_attack;
uint8_t sp_defense;
uint8_t speed;
BaseStats() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {}
BaseStats(uint8_t hp_, uint8_t atk, uint8_t def, uint8_t spa, uint8_t spd, uint8_t spe)
: hp(hp_), attack(atk), defense(def), sp_attack(spa), sp_defense(spd), speed(spe) {}
};
// Effort Values (EVs) - max 510 total, max 255 per stat
struct EffortValues {
uint8_t hp;
uint8_t attack;
uint8_t defense;
uint8_t sp_attack;
uint8_t sp_defense;
uint8_t speed;
EffortValues() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {}
EffortValues(uint8_t hp_, uint8_t atk, uint8_t def, uint8_t spa, uint8_t spd, uint8_t spe)
: hp(hp_), attack(atk), defense(def), sp_attack(spa), sp_defense(spd), speed(spe) {}
// Get total EVs (should not exceed 510)
uint16_t getTotal() const {
return static_cast<uint16_t>(static_cast<uint16_t>(hp) + attack + defense + sp_attack + sp_defense + speed);
}
// Validate EVs (total <= 510, each <= 255)
bool isValid() const {
return getTotal() <= 510;
}
};
// Individual Values (IVs) - 0-31 per stat
// Packed into 32 bits: 5 bits per stat + 2 bits unused
struct IndividualValues {
private:
uint32_t m_packed; // 30 bits used: HP(0-4), ATK(5-9), DEF(10-14), SPA(15-19), SPD(20-24), SPE(25-29)
public:
IndividualValues() : m_packed(0) {}
IndividualValues(uint8_t hp_, uint8_t atk, uint8_t def, uint8_t spa, uint8_t spd, uint8_t spe) {
setHP(hp_);
setAttack(atk);
setDefense(def);
setSpAttack(spa);
setSpDefense(spd);
setSpeed(spe);
}
// Getters
uint8_t getHP() const { return (m_packed & 0x1F); }
uint8_t getAttack() const { return (m_packed >> 5) & 0x1F; }
uint8_t getDefense() const { return (m_packed >> 10) & 0x1F; }
uint8_t getSpAttack() const { return (m_packed >> 15) & 0x1F; }
uint8_t getSpDefense() const { return (m_packed >> 20) & 0x1F; }
uint8_t getSpeed() const { return (m_packed >> 25) & 0x1F; }
// Legacy getters for compatibility
uint8_t hp() const { return getHP(); }
uint8_t attack() const { return getAttack(); }
uint8_t defense() const { return getDefense(); }
uint8_t sp_attack() const { return getSpAttack(); }
uint8_t sp_defense() const { return getSpDefense(); }
uint8_t speed() const { return getSpeed(); }
// Setters
void setHP(uint8_t value) {
if (value > 31) value = 31;
m_packed = (m_packed & ~0x1FU) | (value & 0x1FU);
}
void setAttack(uint8_t value) {
if (value > 31) value = 31;
m_packed = (m_packed & ~(0x1FU << 5)) | ((value & 0x1FU) << 5);
}
void setDefense(uint8_t value) {
if (value > 31) value = 31;
m_packed = (m_packed & ~(0x1FU << 10)) | ((value & 0x1FU) << 10);
}
void setSpAttack(uint8_t value) {
if (value > 31) value = 31;
m_packed = (m_packed & ~(0x1FU << 15)) | ((value & 0x1FU) << 15);
}
void setSpDefense(uint8_t value) {
if (value > 31) value = 31;
m_packed = (m_packed & ~(0x1FU << 20)) | ((value & 0x1FU) << 20);
}
void setSpeed(uint8_t value) {
if (value > 31) value = 31;
m_packed = (m_packed & ~(0x1FU << 25)) | ((value & 0x1FU) << 25);
}
// Validate IVs (each <= 31) - always true with our implementation
bool isValid() const {
return true; // Always valid since we enforce limits in setters
}
};
// Computed battle stat
struct BattleStats {
uint16_t hp;
uint16_t attack;
uint16_t defense;
uint16_t sp_attack;
uint16_t sp_defense;
uint16_t speed;
BattleStats() : hp(0), attack(0), defense(0), sp_attack(0), sp_defense(0), speed(0) {}
BattleStats(uint16_t hp_, uint16_t atk, uint16_t def, uint16_t spa, uint16_t spd, uint16_t spe)
: hp(hp_), attack(atk), defense(def), sp_attack(spa), sp_defense(spd), speed(spe) {}
};
// Pokemon information class - holds data not directly relevant to battle
class PokemonInfo {
public:
PokemonInfo() = default;
PokemonInfo(const BaseStats& baseStats, uint8_t level = 1, Nature nature = Nature::HARDY(),
const IndividualValues& ivs = IndividualValues(),
const EffortValues& evs = EffortValues())
: m_baseStats(baseStats), m_ivs(ivs), m_evs(evs), m_level(level), m_nature(nature) {}
// Getters
const BaseStats& getBaseStats() const { return m_baseStats; }
uint8_t getLevel() const { return m_level; }
Nature getNature() const { return m_nature; }
const IndividualValues& getIVs() const { return m_ivs; }
const EffortValues& getEVs() const { return m_evs; }
// Setters
void setBaseStats(const BaseStats& baseStats) { m_baseStats = baseStats; }
void setLevel(uint8_t level) { m_level = (level > 100) ? 100 : level; }
void setNature(Nature nature) { m_nature = nature; }
void setIVs(const IndividualValues& ivs) { if (ivs.isValid()) m_ivs = ivs; }
void setEVs(const EffortValues& evs) { if (evs.isValid()) m_evs = evs; }
// Calculate battle stats for different generations
template<Generation Gen>
BattleStats calculateBattleStats() const;
private:
BaseStats m_baseStats; // size 6, align 1
IndividualValues m_ivs; // size 6, align 1
EffortValues m_evs; // size 6, align 1
uint8_t m_level = 1; // size 1, align 1
Nature m_nature; // size 1, align 1
};
struct StatCalculatorParams
{
StatCalculatorParams() = default;
StatCalculatorParams(uint8_t base, uint8_t iv, uint8_t ev, uint8_t level, Nature nature, StatIndex statIndex, uint16_t statExp)
: m_base(base), m_iv(iv), m_ev(ev), m_level(level), m_nature(nature), m_statIndex(statIndex), m_statExp(statExp) {}
uint8_t m_base;
uint8_t m_iv;
uint8_t m_ev;
uint8_t m_level;
Nature m_nature;
StatIndex m_statIndex;
uint16_t m_statExp;
};
inline uint16_t CalculateHP_GenI_II(StatCalculatorParams params)
{
// HP=⌊((Base+DV)×2+⌊⌈sqrt(STATEXP)⌉4⌋)×Level100⌋+Level+10
return (((params.m_base + (params.m_iv >> 1u)) << 1u) + (static_cast<uint16_t>(std::ceil(std::sqrt(params.m_statExp))) >> 2u)) * params.m_level / 100u + params.m_level + 10u;
}
inline uint16_t CalculateStat_GenI_II(StatCalculatorParams params)
{
// OtherStat=⌊((Base+DV)×2+⌊⌈sqrt(STATEXP)⌉4⌋)×Level100⌋+5
return (((params.m_base + (params.m_iv >> 1u)) << 1u) + (static_cast<uint16_t>(std::ceil(std::sqrt(params.m_statExp))) >> 2u)) * params.m_level / 100u + 5u;
}
template <Generation Gen>
uint16_t CalculateHP(StatCalculatorParams params);
template <Generation Gen>
uint16_t CalculateStat(StatCalculatorParams params);
template <> inline uint16_t CalculateHP<Generation::I>(StatCalculatorParams params) { return CalculateHP_GenI_II(params); }
template <> inline uint16_t CalculateHP<Generation::II>(StatCalculatorParams params) { return CalculateHP_GenI_II(params); }
template <> inline uint16_t CalculateStat<Generation::I>(StatCalculatorParams params) { return CalculateStat_GenI_II(params); }
template <> inline uint16_t CalculateStat<Generation::II>(StatCalculatorParams params) { return CalculateStat_GenI_II(params); }
template <Generation Gen>
inline uint16_t CalculateHP(StatCalculatorParams params)
{
// HP=⌊(2×Base+IV+⌊EV4⌋)×Level100⌋+Level+10
return ((2 * params.m_base + params.m_iv + (params.m_ev >> 2)) * params.m_level / 100) + params.m_level + 10;
}
template <Generation Gen>
inline uint16_t CalculateStat(StatCalculatorParams params)
{
// OtherStat=⌊(⌊(2×Base+IV+⌊EV4⌋)×Level100⌋+5)×Nature⌋
return (((2 * params.m_base + params.m_iv + (params.m_ev >> 2)) * params.m_level / 100) + 5) * params.m_nature.getMultiplier10(params.m_statIndex) / 10;
}
} // namespace PokEng
#endif // STATS_H

View File

@@ -3,9 +3,12 @@
#include <cstdint>
#include <array>
#include <string>
#include <string_view>
#include <optional>
#include <vector>
#include <memory>
#include <span>
#include "config.h"
@@ -39,6 +42,9 @@ enum class Type : uint8_t {
TYPE_COUNT // Keep this last for array sizing
};
constexpr size_t TYPE_COUNT = static_cast<size_t>(Type::TYPE_COUNT);
constexpr size_t TYPE_CHART_SIZE = TYPE_COUNT * TYPE_COUNT;
// Type multipliers as integers (multiply by 2 for 0.5x, 4 for 0.25x, etc.)
enum class TypeMultiplier : uint8_t {
ZERO = 0, // 0x damage (immune)
@@ -49,16 +55,6 @@ enum class TypeMultiplier : uint8_t {
QUADRUPLE = 16 // 4x damage
};
// Compile-time type chart traits
template <Generation Gen>
struct TypeChartTraits {
static constexpr size_t TYPE_COUNT = static_cast<size_t>(Type::TYPE_COUNT);
static constexpr size_t CHART_SIZE = TYPE_COUNT * TYPE_COUNT;
// Each generation has its own type chart
static const std::array<TypeMultiplier, CHART_SIZE>& getTypeChart();
};
// Pokemon type representation
class PokemonTypes {
public:
@@ -95,21 +91,13 @@ public:
template <Generation Gen>
static uint32_t calculateDamageMultiplier(Type attackType, const PokemonTypes& defenderTypes);
// Load type chart from JSON file
// Get type chart for a specific generation
template <Generation Gen>
static bool loadTypeChartFromFile(const std::string& filename);
static const std::span<const TypeMultiplier> getTypeChart();
public:
// Type chart storage for each generation (public for template access)
static std::array<TypeMultiplier, TypeChartTraits<Generation::I>::CHART_SIZE> s_gen1Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::II>::CHART_SIZE> s_gen2Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::III>::CHART_SIZE> s_gen3Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::IV>::CHART_SIZE> s_gen4Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::V>::CHART_SIZE> s_gen5Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::VI>::CHART_SIZE> s_gen6Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::VII>::CHART_SIZE> s_gen7Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::VIII>::CHART_SIZE> s_gen8Chart;
static std::array<TypeMultiplier, TypeChartTraits<Generation::IX>::CHART_SIZE> s_gen9Chart;
static std::array<std::span<const TypeMultiplier>, static_cast<size_t>(Generation::IX) + 1> s_typeChart;
};
// High-performance damage calculation
@@ -123,60 +111,12 @@ inline uint32_t calculateDamage(uint32_t baseDamage, Type attackType, const Poke
return (baseDamage * rawMultiplier) / static_cast<uint32_t>(TypeMultiplier::NEUTRAL);
}
// Template specializations for type chart access
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::I>::CHART_SIZE>&
TypeChartTraits<Generation::I>::getTypeChart() {
return TypeUtils::s_gen1Chart;
template <Generation Gen>
inline const std::span<const TypeMultiplier> TypeUtils::getTypeChart() {
return s_typeChart[static_cast<size_t>(Gen)];
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::II>::CHART_SIZE>&
TypeChartTraits<Generation::II>::getTypeChart() {
return TypeUtils::s_gen2Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::III>::CHART_SIZE>&
TypeChartTraits<Generation::III>::getTypeChart() {
return TypeUtils::s_gen3Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::IV>::CHART_SIZE>&
TypeChartTraits<Generation::IV>::getTypeChart() {
return TypeUtils::s_gen4Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::V>::CHART_SIZE>&
TypeChartTraits<Generation::V>::getTypeChart() {
return TypeUtils::s_gen5Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::VI>::CHART_SIZE>&
TypeChartTraits<Generation::VI>::getTypeChart() {
return TypeUtils::s_gen6Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::VII>::CHART_SIZE>&
TypeChartTraits<Generation::VII>::getTypeChart() {
return TypeUtils::s_gen7Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::VIII>::CHART_SIZE>&
TypeChartTraits<Generation::VIII>::getTypeChart() {
return TypeUtils::s_gen8Chart;
}
template <>
inline const std::array<TypeMultiplier, TypeChartTraits<Generation::IX>::CHART_SIZE>&
TypeChartTraits<Generation::IX>::getTypeChart() {
return TypeUtils::s_gen9Chart;
}
void initializeTypeCharts();
} // namespace PokEng

View File

@@ -1,17 +0,0 @@
#ifndef POKEMON_BATTLE_SIM_H
#define POKEMON_BATTLE_SIM_H
// Main header file for Pokemon Battle Simulator
// Includes all core functionality
#include "core/types.h"
#include "core/pokemon.h"
#include "core/battle.h"
#include "core/config.h"
// Forward declarations for functions
namespace PokEng {
bool simulateBattle(Pokemon& pokemon1, Pokemon& pokemon2);
}
#endif // POKEMON_BATTLE_SIM_H

372
src/core/pokemon_table.cpp Normal file
View File

@@ -0,0 +1,372 @@
#include "core/pokemon_table.h"
#include "../thirdParty/rapidjson/document.h"
#include "../thirdParty/rapidjson/filereadstream.h"
#include "../thirdParty/rapidjson/error/en.h"
#include <filesystem>
#include <fstream>
#include <iostream>
#include <algorithm>
#include <cassert>
namespace PokEng {
namespace fs = std::filesystem;
// Global Pokemon table instance
std::unique_ptr<PokemonTable> g_pokemonTable;
bool PokemonTable::loadFromDataDirectory() {
// Clear any existing data
clear();
// Get the path to the data directory relative to the executable
fs::path dataDir = fs::current_path() / "data" / "pokemon";
// If not found, try relative to the build directory (common in CMake builds)
if (!fs::exists(dataDir)) {
dataDir = fs::current_path() / ".." / "data" / "pokemon";
}
// If still not found, try a few more common locations
if (!fs::exists(dataDir)) {
dataDir = fs::current_path() / "data" / "pokemon";
if (!fs::exists(dataDir)) {
std::cerr << "Error: Could not find Pokemon data directory at: " << dataDir << std::endl;
return false;
}
}
std::vector<std::string> jsonFiles;
// Find all JSON files in the pokemon data directory
for (const auto& entry : fs::directory_iterator(dataDir)) {
if (entry.is_regular_file() && entry.path().extension() == ".json") {
jsonFiles.push_back(entry.path().string());
}
}
if (jsonFiles.empty()) {
std::cerr << "Error: No Pokemon JSON files found in: " << dataDir << std::endl;
return false;
}
// Sort files to ensure consistent loading order
std::sort(jsonFiles.begin(), jsonFiles.end());
std::cout << "Found " << jsonFiles.size() << " Pokemon data files to load" << std::endl;
return loadFromFiles(jsonFiles);
}
bool PokemonTable::loadFromFiles(const std::vector<std::string>& filePaths) {
clear();
bool success = true;
size_t totalPokemonLoaded = 0;
for (const auto& filePath : filePaths) {
if (!parsePokemonFile(filePath)) {
std::cerr << "Failed to parse Pokemon file: " << filePath << std::endl;
success = false;
continue;
}
// Count Pokemon in this file (rough estimate)
std::ifstream file(filePath);
if (file.is_open()) {
std::string content((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
size_t pokemonCount = std::count(content.begin(), content.end(), '{');
totalPokemonLoaded += pokemonCount / 2; // Rough estimate
}
}
if (success && !m_pokemonSpecies.empty()) {
std::cout << "Successfully loaded " << size() << " Pokemon species" << std::endl;
std::cout << "Max Pokemon ID: " << getMaxId() << std::endl;
}
return success && !m_pokemonSpecies.empty();
}
bool PokemonTable::parsePokemonFile(const std::string& filePath) {
using namespace rapidjson;
// Open the file
FILE* fp = fopen(filePath.c_str(), "rb");
if (!fp) {
std::cerr << "Error: Could not open file: " << filePath << std::endl;
return false;
}
// Create a file read stream
char readBuffer[65536];
FileReadStream is(fp, readBuffer, sizeof(readBuffer));
// Parse the JSON document
Document doc;
doc.ParseStream(is);
// Check for parse errors
if (doc.HasParseError()) {
std::cerr << "JSON parse error in file " << filePath << ": "
<< GetParseError_En(doc.GetParseError()) << std::endl;
fclose(fp);
return false;
}
// Close the file
fclose(fp);
// Verify it's an array
if (!doc.IsArray()) {
std::cerr << "Error: Expected JSON array in file: " << filePath << std::endl;
return false;
}
// Parse each Pokemon in the array
for (const auto& pokemonValue : doc.GetArray()) {
if (!pokemonValue.IsObject()) {
std::cerr << "Warning: Skipping non-object entry in " << filePath << std::endl;
continue;
}
try {
PokemonSpecies species = parsePokemonJson(&pokemonValue);
// Ensure the vector is large enough
if (species.id >= m_pokemonSpecies.size()) {
m_pokemonSpecies.resize(species.id + 1);
}
// Store the Pokemon
m_pokemonSpecies[species.id] = species;
// Update the name-to-ID mapping
m_nameToIdMap[species.name] = species.id;
// Update max ID
if (species.id > m_maxId) {
m_maxId = species.id;
}
} catch (const std::exception& e) {
std::cerr << "Error parsing Pokemon in " << filePath << ": " << e.what() << std::endl;
continue;
}
}
return true;
}
PokemonSpecies PokemonTable::parsePokemonJson(const void* pokemonJson) {
using namespace rapidjson;
const Value* pokemonValue = static_cast<const Value*>(pokemonJson);
PokemonSpecies species;
// Parse ID
if (pokemonValue->HasMember("id") && (*pokemonValue)["id"].IsUint()) {
species.id = static_cast<uint16_t>((*pokemonValue)["id"].GetUint());
} else {
throw std::runtime_error("Missing or invalid 'id' field");
}
// Parse name
if (pokemonValue->HasMember("name") && (*pokemonValue)["name"].IsString()) {
species.name = (*pokemonValue)["name"].GetString();
} else {
throw std::runtime_error("Missing or invalid 'name' field");
}
// Parse base stats
if (pokemonValue->HasMember("stats") && (*pokemonValue)["stats"].IsObject()) {
species.base_stats = parseBaseStats(&(*pokemonValue)["stats"]);
} else {
throw std::runtime_error("Missing or invalid 'stats' field");
}
// Parse types
if (pokemonValue->HasMember("types") && (*pokemonValue)["types"].IsArray()) {
species.types = parseTypes(&(*pokemonValue)["types"]);
} else {
throw std::runtime_error("Missing or invalid 'types' field");
}
return species;
}
BaseStats PokemonTable::parseBaseStats(const void* statsJson) {
using namespace rapidjson;
const Value* statsValue = static_cast<const Value*>(statsJson);
BaseStats baseStats;
// Helper function to safely get stat value
auto getStatValue = [](const Value& obj, const char* key) -> uint8_t {
if (obj.HasMember(key) && obj[key].IsUint()) {
return static_cast<uint8_t>(std::min(obj[key].GetUint(), 255u));
}
return 0;
};
baseStats.hp = getStatValue(*statsValue, "hp");
baseStats.attack = getStatValue(*statsValue, "attack");
baseStats.defense = getStatValue(*statsValue, "defense");
baseStats.sp_attack = getStatValue(*statsValue, "special-attack");
baseStats.sp_defense = getStatValue(*statsValue, "special-defense");
baseStats.speed = getStatValue(*statsValue, "speed");
return baseStats;
}
PokemonTypes PokemonTable::parseTypes(const void* typesJson) {
using namespace rapidjson;
const Value* typesValue = static_cast<const Value*>(typesJson);
PokemonTypes types;
if (typesValue->Empty()) {
return types; // Return empty types
}
// Get the first type (primary)
if (typesValue->Size() > 0) {
const auto& firstType = (*typesValue)[0];
if (firstType.IsString()) {
std::string typeStr = firstType.GetString();
auto type = TypeUtils::stringToType(typeStr);
if (type) {
types.setPrimary(*type);
}
}
}
// Get the second type (secondary) if it exists
if (typesValue->Size() > 1) {
const auto& secondType = (*typesValue)[1];
if (secondType.IsString()) {
std::string typeStr = secondType.GetString();
auto type = TypeUtils::stringToType(typeStr);
if (type) {
types.setSecondary(*type);
}
}
}
return types;
}
const PokemonSpecies* PokemonTable::getPokemon(uint16_t id) const {
if (id == 0 || id >= m_pokemonSpecies.size()) {
return nullptr;
}
return &m_pokemonSpecies[id];
}
const PokemonSpecies* PokemonTable::getPokemonByName(std::string_view name) const {
auto it = m_nameToIdMap.find(std::string(name));
if (it == m_nameToIdMap.end()) {
return nullptr;
}
return getPokemon(it->second);
}
bool PokemonTable::hasPokemon(uint16_t id) const {
return id > 0 && id < m_pokemonSpecies.size() && m_pokemonSpecies[id].id != 0;
}
size_t PokemonTable::size() const {
// Count non-empty entries (ID != 0)
return std::count_if(m_pokemonSpecies.begin(), m_pokemonSpecies.end(),
[](const PokemonSpecies& species) { return species.id != 0; });
}
bool PokemonTable::empty() const {
return m_pokemonSpecies.empty() || size() == 0;
}
uint16_t PokemonTable::getMaxId() const {
return m_maxId;
}
void PokemonTable::clear() {
m_pokemonSpecies.clear();
m_nameToIdMap.clear();
m_maxId = 0;
}
const std::vector<PokemonSpecies>& PokemonTable::getAllPokemon() const {
return m_pokemonSpecies;
}
bool PokemonTable::validate() const {
if (empty()) {
return false;
}
// Check that all Pokemon have valid IDs
for (uint16_t id = 1; id <= m_maxId; ++id) {
const auto* pokemon = getPokemon(id);
if (pokemon) {
if (pokemon->id != id) {
std::cerr << "Validation error: Pokemon at ID " << id
<< " has mismatched ID " << pokemon->id << std::endl;
return false;
}
if (pokemon->name.empty()) {
std::cerr << "Validation error: Pokemon ID " << id
<< " has empty name" << std::endl;
return false;
}
}
}
// Check name-to-ID mapping consistency
for (const auto& pair : m_nameToIdMap) {
const auto* pokemon = getPokemon(pair.second);
if (!pokemon || pokemon->name != pair.first) {
std::cerr << "Validation error: Name-to-ID mapping inconsistency for '"
<< pair.first << "'" << std::endl;
return false;
}
}
return true;
}
bool initializePokemonTable() {
if (g_pokemonTable) {
std::cout << "Warning: Pokemon table already initialized" << std::endl;
return true;
}
g_pokemonTable = std::make_unique<PokemonTable>();
if (!g_pokemonTable->loadFromDataDirectory()) {
std::cerr << "Failed to initialize Pokemon table" << std::endl;
g_pokemonTable.reset();
return false;
}
if (!g_pokemonTable->validate()) {
std::cerr << "Pokemon table validation failed" << std::endl;
g_pokemonTable.reset();
return false;
}
std::cout << "Pokemon table initialized successfully with "
<< g_pokemonTable->size() << " Pokemon" << std::endl;
return true;
}
void shutdownPokemonTable() {
if (g_pokemonTable) {
std::cout << "Shutting down Pokemon table" << std::endl;
g_pokemonTable.reset();
}
}
} // namespace PokEng

View File

@@ -1,4 +1,5 @@
#include "pokemon_battle_sim.h"
#include "core/config.h"
#include "core/types.h"
#include "../thirdParty/rapidjson/document.h"
#include "../thirdParty/rapidjson/filereadstream.h"
#include <cstdio>
@@ -8,16 +9,6 @@
namespace PokEng {
// Static type chart storage initialization
std::array<TypeMultiplier, TypeChartTraits<Generation::I>::CHART_SIZE> TypeUtils::s_gen1Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::II>::CHART_SIZE> TypeUtils::s_gen2Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::III>::CHART_SIZE> TypeUtils::s_gen3Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::IV>::CHART_SIZE> TypeUtils::s_gen4Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::V>::CHART_SIZE> TypeUtils::s_gen5Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::VI>::CHART_SIZE> TypeUtils::s_gen6Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::VII>::CHART_SIZE> TypeUtils::s_gen7Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::VIII>::CHART_SIZE> TypeUtils::s_gen8Chart;
std::array<TypeMultiplier, TypeChartTraits<Generation::IX>::CHART_SIZE> TypeUtils::s_gen9Chart;
// String to type mapping
static const std::unordered_map<std::string_view, Type> s_stringToTypeMap = {
@@ -87,103 +78,35 @@ std::string_view TypeUtils::typeToString(Type type) {
}
template <Generation Gen>
TypeMultiplier TypeUtils::getTypeEffectiveness(Type attackType, Type defendType) {
if (attackType == Type::NONE || defendType == Type::NONE) {
return TypeMultiplier::NEUTRAL;
}
const auto& chart = TypeChartTraits<Gen>::getTypeChart();
size_t attackIdx = static_cast<size_t>(attackType);
size_t defendIdx = static_cast<size_t>(defendType);
size_t index = attackIdx * static_cast<size_t>(Type::TYPE_COUNT) + defendIdx;
if (index < chart.size()) {
return chart[index];
}
return TypeMultiplier::NEUTRAL;
TypeMultiplier TypeUtils::getTypeEffectiveness(Type attackType, Type defendType)
{
size_t index = static_cast<uint8_t>(attackType) * static_cast<uint8_t>(Type::TYPE_COUNT) + static_cast<uint8_t>(defendType);
return TypeUtils::getTypeChart<Gen>()[index];
}
// Helper function to convert TypeMultiplier enum to actual multiplier value
static float typeMultiplierToFloat(TypeMultiplier multiplier) {
switch (multiplier) {
case TypeMultiplier::ZERO: return 0.0f;
case TypeMultiplier::QUARTER: return 0.25f;
case TypeMultiplier::HALF: return 0.5f;
case TypeMultiplier::NEUTRAL: return 1.0f;
case TypeMultiplier::DOUBLE: return 2.0f;
case TypeMultiplier::QUADRUPLE: return 4.0f;
default: return 1.0f;
}
}
// Example of the JSON file format
// "normal": {
// "double_damage_from": [
// "fighting"
// ],
// "double_damage_to": [],
// "half_damage_from": [],
// "half_damage_to": [
// "rock",
// "steel"
// ],
// "no_damage_from": [
// "ghost"
// ],
// "no_damage_to": [
// "ghost"
// ]
// }
// Helper function to convert float multiplier back to integer representation
static uint32_t floatToMultiplierInt(float multiplier) {
if (multiplier == 0.0f) return static_cast<uint32_t>(TypeMultiplier::ZERO);
if (multiplier == 0.25f) return static_cast<uint32_t>(TypeMultiplier::QUARTER);
if (multiplier == 0.5f) return static_cast<uint32_t>(TypeMultiplier::HALF);
if (multiplier == 1.0f) return static_cast<uint32_t>(TypeMultiplier::NEUTRAL);
if (multiplier == 2.0f) return static_cast<uint32_t>(TypeMultiplier::DOUBLE);
if (multiplier == 4.0f) return static_cast<uint32_t>(TypeMultiplier::QUADRUPLE);
return static_cast<uint32_t>(TypeMultiplier::NEUTRAL);
}
template <Generation Gen>
uint32_t TypeUtils::calculateDamageMultiplier(Type attackType, const PokemonTypes& defenderTypes) {
if (attackType == Type::NONE) {
return static_cast<uint32_t>(TypeMultiplier::NEUTRAL);
}
// Get effectiveness against primary type and convert to float
float multiplier = typeMultiplierToFloat(getTypeEffectiveness<Gen>(attackType, defenderTypes.getPrimary()));
// If there's a secondary type, multiply by its effectiveness
if (defenderTypes.hasSecondary()) {
float secondaryMultiplier = typeMultiplierToFloat(getTypeEffectiveness<Gen>(attackType, defenderTypes.getSecondary()));
multiplier *= secondaryMultiplier;
}
// Convert back to integer representation
return floatToMultiplierInt(multiplier);
}
// Explicit template instantiations for all generations
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::I>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::II>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::III>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::IV>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::V>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::VI>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::VII>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::VIII>(Type, Type);
template TypeMultiplier TypeUtils::getTypeEffectiveness<Generation::IX>(Type, Type);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::I>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::II>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::III>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::IV>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::V>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::VI>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::VII>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::VIII>(Type, const PokemonTypes&);
template uint32_t TypeUtils::calculateDamageMultiplier<Generation::IX>(Type, const PokemonTypes&);
// Convert float damage factor to TypeMultiplier
static TypeMultiplier floatToTypeMultiplier(double factor) {
if (factor == 0.0) return TypeMultiplier::ZERO;
if (factor == 0.25) return TypeMultiplier::QUARTER;
if (factor == 0.5) return TypeMultiplier::HALF;
if (factor == 1.0) return TypeMultiplier::NEUTRAL;
if (factor == 2.0) return TypeMultiplier::DOUBLE;
if (factor == 4.0) return TypeMultiplier::QUADRUPLE;
return TypeMultiplier::NEUTRAL; // Default fallback
}
template <Generation Gen>
bool TypeUtils::loadTypeChartFromFile(const std::string& filename) {
std::array<TypeMultiplier, TYPE_CHART_SIZE> loadTypeChartFromFile(const std::string& filename) {
FILE* fp = fopen(filename.c_str(), "r");
if (!fp) {
return false;
return std::array<TypeMultiplier, TYPE_CHART_SIZE>{};
}
char readBuffer[65536];
@@ -193,116 +116,168 @@ bool TypeUtils::loadTypeChartFromFile(const std::string& filename) {
doc.ParseStream(is);
fclose(fp);
if (doc.HasParseError() || !doc.IsArray()) {
return false;
if (doc.HasParseError() || !doc.IsObject()) {
return std::array<TypeMultiplier, TYPE_CHART_SIZE>{};
}
// Initialize the chart with neutral values
// Note: We access the static members directly since getTypeChart() returns const reference
if constexpr (Gen == Generation::I) {
std::fill(TypeUtils::s_gen1Chart.begin(), TypeUtils::s_gen1Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::II) {
std::fill(TypeUtils::s_gen2Chart.begin(), TypeUtils::s_gen2Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::III) {
std::fill(TypeUtils::s_gen3Chart.begin(), TypeUtils::s_gen3Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::IV) {
std::fill(TypeUtils::s_gen4Chart.begin(), TypeUtils::s_gen4Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::V) {
std::fill(TypeUtils::s_gen5Chart.begin(), TypeUtils::s_gen5Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::VI) {
std::fill(TypeUtils::s_gen6Chart.begin(), TypeUtils::s_gen6Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::VII) {
std::fill(TypeUtils::s_gen7Chart.begin(), TypeUtils::s_gen7Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::VIII) {
std::fill(TypeUtils::s_gen8Chart.begin(), TypeUtils::s_gen8Chart.end(), TypeMultiplier::NEUTRAL);
} else if constexpr (Gen == Generation::IX) {
std::fill(TypeUtils::s_gen9Chart.begin(), TypeUtils::s_gen9Chart.end(), TypeMultiplier::NEUTRAL);
}
// Create and initialize type chart with neutral effectiveness
auto typeChart = std::array<TypeMultiplier, TYPE_CHART_SIZE>();
typeChart.fill(TypeMultiplier::NEUTRAL);
// Parse JSON and populate type chart
for (const auto& entry : doc.GetArray()) {
if (!entry.IsObject()) continue;
for (auto it = doc.MemberBegin(); it != doc.MemberEnd(); ++it) {
const std::string defendingTypeStr = it->name.GetString();
auto defendingTypeOpt = TypeUtils::stringToType(defendingTypeStr);
if (!entry.HasMember("attacking_type") || !entry.HasMember("defending_type") ||
!entry.HasMember("damage_factor")) {
if (!defendingTypeOpt.has_value()) {
continue; // Skip unknown types
}
Type defendingType = defendingTypeOpt.value();
const auto& typeData = it->value;
if (!typeData.IsObject()) {
continue;
}
const auto& attackTypeStr = entry["attacking_type"].GetString();
const auto& defendTypeStr = entry["defending_type"].GetString();
double damageFactor = entry["damage_factor"].GetDouble();
auto attackTypeOpt = stringToType(attackTypeStr);
auto defendTypeOpt = stringToType(defendTypeStr);
if (!attackTypeOpt || !defendTypeOpt) {
continue;
// Process double_damage_from (types that deal 2x damage to this type)
if (typeData.HasMember("double_damage_from") && typeData["double_damage_from"].IsArray()) {
for (const auto& attackTypeVal : typeData["double_damage_from"].GetArray()) {
if (attackTypeVal.IsString()) {
auto attackTypeOpt = TypeUtils::stringToType(attackTypeVal.GetString());
if (attackTypeOpt.has_value()) {
size_t attackIdx = static_cast<size_t>(attackTypeOpt.value());
size_t defendIdx = static_cast<size_t>(defendingType);
size_t index = attackIdx * TYPE_COUNT + defendIdx;
typeChart[index] = TypeMultiplier::DOUBLE;
}
}
}
}
Type attackType = *attackTypeOpt;
Type defendType = *defendTypeOpt;
TypeMultiplier multiplier = floatToTypeMultiplier(damageFactor);
// Process half_damage_from (types that deal 0.5x damage to this type)
if (typeData.HasMember("half_damage_from") && typeData["half_damage_from"].IsArray()) {
for (const auto& attackTypeVal : typeData["half_damage_from"].GetArray()) {
if (attackTypeVal.IsString()) {
auto attackTypeOpt = TypeUtils::stringToType(attackTypeVal.GetString());
if (attackTypeOpt.has_value()) {
size_t attackIdx = static_cast<size_t>(attackTypeOpt.value());
size_t defendIdx = static_cast<size_t>(defendingType);
size_t index = attackIdx * TYPE_COUNT + defendIdx;
typeChart[index] = TypeMultiplier::HALF;
}
}
}
}
size_t attackIdx = static_cast<size_t>(attackType);
size_t defendIdx = static_cast<size_t>(defendType);
size_t index = attackIdx * static_cast<size_t>(Type::TYPE_COUNT) + defendIdx;
size_t chartSize = static_cast<size_t>(Type::TYPE_COUNT) * static_cast<size_t>(Type::TYPE_COUNT);
// Process no_damage_from (types that deal 0x damage to this type)
if (typeData.HasMember("no_damage_from") && typeData["no_damage_from"].IsArray()) {
for (const auto& attackTypeVal : typeData["no_damage_from"].GetArray()) {
if (attackTypeVal.IsString()) {
auto attackTypeOpt = TypeUtils::stringToType(attackTypeVal.GetString());
if (attackTypeOpt.has_value()) {
size_t attackIdx = static_cast<size_t>(attackTypeOpt.value());
size_t defendIdx = static_cast<size_t>(defendingType);
size_t index = attackIdx * TYPE_COUNT + defendIdx;
typeChart[index] = TypeMultiplier::ZERO;
}
}
}
}
if (index < chartSize) {
// Direct assignment to static members
if constexpr (Gen == Generation::I) {
TypeUtils::s_gen1Chart[index] = multiplier;
} else if constexpr (Gen == Generation::II) {
TypeUtils::s_gen2Chart[index] = multiplier;
} else if constexpr (Gen == Generation::III) {
TypeUtils::s_gen3Chart[index] = multiplier;
} else if constexpr (Gen == Generation::IV) {
TypeUtils::s_gen4Chart[index] = multiplier;
} else if constexpr (Gen == Generation::V) {
TypeUtils::s_gen5Chart[index] = multiplier;
} else if constexpr (Gen == Generation::VI) {
TypeUtils::s_gen6Chart[index] = multiplier;
} else if constexpr (Gen == Generation::VII) {
TypeUtils::s_gen7Chart[index] = multiplier;
} else if constexpr (Gen == Generation::VIII) {
TypeUtils::s_gen8Chart[index] = multiplier;
} else if constexpr (Gen == Generation::IX) {
TypeUtils::s_gen9Chart[index] = multiplier;
// Process double_damage_to (types this type deals 2x damage to)
if (typeData.HasMember("double_damage_to") && typeData["double_damage_to"].IsArray()) {
for (const auto& defendTypeVal : typeData["double_damage_to"].GetArray()) {
if (defendTypeVal.IsString()) {
auto defendTypeOpt = TypeUtils::stringToType(defendTypeVal.GetString());
if (defendTypeOpt.has_value()) {
size_t attackIdx = static_cast<size_t>(defendingType);
size_t defendIdx = static_cast<size_t>(defendTypeOpt.value());
size_t index = attackIdx * TYPE_COUNT + defendIdx;
typeChart[index] = TypeMultiplier::DOUBLE;
}
}
}
}
// Process half_damage_to (types this type deals 0.5x damage to)
if (typeData.HasMember("half_damage_to") && typeData["half_damage_to"].IsArray()) {
for (const auto& defendTypeVal : typeData["half_damage_to"].GetArray()) {
if (defendTypeVal.IsString()) {
auto defendTypeOpt = TypeUtils::stringToType(defendTypeVal.GetString());
if (defendTypeOpt.has_value()) {
size_t attackIdx = static_cast<size_t>(defendingType);
size_t defendIdx = static_cast<size_t>(defendTypeOpt.value());
size_t index = attackIdx * TYPE_COUNT + defendIdx;
typeChart[index] = TypeMultiplier::HALF;
}
}
}
}
// Process no_damage_to (types this type deals 0x damage to)
if (typeData.HasMember("no_damage_to") && typeData["no_damage_to"].IsArray()) {
for (const auto& defendTypeVal : typeData["no_damage_to"].GetArray()) {
if (defendTypeVal.IsString()) {
auto defendTypeOpt = TypeUtils::stringToType(defendTypeVal.GetString());
if (defendTypeOpt.has_value()) {
size_t attackIdx = static_cast<size_t>(defendingType);
size_t defendIdx = static_cast<size_t>(defendTypeOpt.value());
size_t index = attackIdx * TYPE_COUNT + defendIdx;
typeChart[index] = TypeMultiplier::ZERO;
}
}
}
}
}
return true;
return typeChart;
}
// Explicit template instantiations for loading
template bool TypeUtils::loadTypeChartFromFile<Generation::I>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::II>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::III>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::IV>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::V>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::VI>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::VII>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::VIII>(const std::string&);
template bool TypeUtils::loadTypeChartFromFile<Generation::IX>(const std::string&);
bool compareTypeChart(const std::array<TypeMultiplier, TYPE_CHART_SIZE>& chart1, const std::array<TypeMultiplier, TYPE_CHART_SIZE>& chart2) {
return std::equal(chart1.begin(), chart1.end(), chart2.begin());
}
std::span<const TypeMultiplier> getDuplicateTypeChart(const std::array<TypeMultiplier, TYPE_CHART_SIZE>& chart)
{
static std::vector<std::array<TypeMultiplier, TYPE_CHART_SIZE>> allCharts;
allCharts.reserve(static_cast<size_t>(Generation::IX) + 1);
// Check if the chart is already in the list
for (const auto& otherChart : allCharts) {
if (compareTypeChart(chart, otherChart)) {
return std::span<const TypeMultiplier>(otherChart);
}
}
allCharts.push_back(chart);
return std::span<const TypeMultiplier>(allCharts.back());
}
// Initialize type charts on startup
struct TypeChartInitializer {
TypeChartInitializer() {
// Load type charts for each generation
TypeUtils::loadTypeChartFromFile<Generation::I>("../data/type_effectiveness_generation-i.json");
TypeUtils::loadTypeChartFromFile<Generation::II>("../data/type_effectiveness_generation-ii.json");
TypeUtils::loadTypeChartFromFile<Generation::III>("../data/type_effectiveness_generation-iii.json");
TypeUtils::loadTypeChartFromFile<Generation::IV>("../data/type_effectiveness_generation-iv.json");
TypeUtils::loadTypeChartFromFile<Generation::V>("../data/type_effectiveness_generation-v.json");
TypeUtils::loadTypeChartFromFile<Generation::VI>("../data/type_effectiveness_generation-vi.json");
TypeUtils::loadTypeChartFromFile<Generation::VII>("../data/type_effectiveness_generation-vii.json");
TypeUtils::loadTypeChartFromFile<Generation::VIII>("../data/type_effectiveness_generation-viii.json");
TypeUtils::loadTypeChartFromFile<Generation::IX>("../data/type_effectiveness_generation-ix.json");
}
void initializeTypeCharts() {
// Load type charts for each generation and store them in static arrays
TypeUtils::s_typeChart[static_cast<size_t>(Generation::I)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-i.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::II)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-ii.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::III)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-iii.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::IV)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-iv.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::V)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-v.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::VI)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-vi.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::VII)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-vii.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::VIII)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-viii.json"));
TypeUtils::s_typeChart[static_cast<size_t>(Generation::IX)] =
getDuplicateTypeChart(loadTypeChartFromFile("../data/types/generation-ix.json"));
};
// Static initializer to load type charts at program startup
static TypeChartInitializer s_initializer;
// Definition of the static type chart array
std::array<std::span<const TypeMultiplier>, static_cast<size_t>(Generation::IX) + 1> TypeUtils::s_typeChart;
} // namespace PokEng

16
src/main.cpp Normal file
View File

@@ -0,0 +1,16 @@
#include <iostream>
#include "core/types.h"
#include "core/pokemon_table.h"
using namespace PokEng;
int main() {
initializeTypeCharts();
initializePokemonTable();
}

View File

@@ -1,8 +0,0 @@
# Configure the project
cmake -B build -S .
# Build the project (includes tests)
cmake --build build
# Run all tests
cmake --build build --target test

View File

@@ -0,0 +1,107 @@
#include <gtest/gtest.h>
#include "core/pokemon_table.h"
using namespace PokEng;
class PokemonTableTest : public ::testing::Test {
protected:
void SetUp() override {
// Initialize the global Pokemon table for each test
ASSERT_TRUE(initializePokemonTable());
}
void TearDown() override {
// Clean up the global Pokemon table after each test
shutdownPokemonTable();
}
};
TEST_F(PokemonTableTest, Initialization) {
ASSERT_TRUE(g_pokemonTable != nullptr);
EXPECT_GT(g_pokemonTable->size(), 0);
EXPECT_GT(g_pokemonTable->getMaxId(), 0);
}
TEST_F(PokemonTableTest, BulbasaurLookup) {
const auto* bulbasaur = g_pokemonTable->getPokemon(1);
ASSERT_TRUE(bulbasaur != nullptr);
EXPECT_EQ(bulbasaur->id, 1);
EXPECT_EQ(bulbasaur->name, "bulbasaur");
EXPECT_EQ(bulbasaur->base_stats.hp, 45);
EXPECT_EQ(bulbasaur->base_stats.attack, 49);
EXPECT_EQ(bulbasaur->base_stats.defense, 49);
EXPECT_EQ(bulbasaur->base_stats.sp_attack, 65);
EXPECT_EQ(bulbasaur->base_stats.sp_defense, 65);
EXPECT_EQ(bulbasaur->base_stats.speed, 45);
// Check types
EXPECT_EQ(bulbasaur->types.getPrimary(), Type::GRASS);
EXPECT_EQ(bulbasaur->types.getSecondary(), Type::POISON);
}
TEST_F(PokemonTableTest, NameBasedLookup) {
const auto* charizard = g_pokemonTable->getPokemonByName("charizard");
ASSERT_TRUE(charizard != nullptr);
EXPECT_EQ(charizard->id, 6); // Charizard's ID
EXPECT_EQ(charizard->name, "charizard");
}
TEST_F(PokemonTableTest, InvalidIdLookup) {
const auto* invalid = g_pokemonTable->getPokemon(99999);
EXPECT_TRUE(invalid == nullptr);
// Test ID 0 (should be invalid)
const auto* zero = g_pokemonTable->getPokemon(0);
EXPECT_TRUE(zero == nullptr);
}
TEST_F(PokemonTableTest, InvalidNameLookup) {
const auto* invalid = g_pokemonTable->getPokemonByName("nonexistentpokemon");
EXPECT_TRUE(invalid == nullptr);
}
TEST_F(PokemonTableTest, HasPokemonFunction) {
EXPECT_TRUE(g_pokemonTable->hasPokemon(1)); // Bulbasaur
EXPECT_TRUE(g_pokemonTable->hasPokemon(150)); // Mewtwo
EXPECT_FALSE(g_pokemonTable->hasPokemon(0));
EXPECT_FALSE(g_pokemonTable->hasPokemon(99999));
}
TEST_F(PokemonTableTest, PerformanceTest) {
// Test that lookups are fast enough (less than 1ms for 1000 lookups)
auto start = std::chrono::high_resolution_clock::now();
for (int i = 0; i < 1000; ++i) {
uint16_t id = (i % g_pokemonTable->getMaxId()) + 1;
const auto* pokemon = g_pokemonTable->getPokemon(id);
ASSERT_TRUE(pokemon != nullptr);
// Just access some data to ensure the pointer is valid
volatile uint16_t hp = pokemon->base_stats.hp;
(void)hp; // Prevent optimization
}
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
// Should be much faster than 1ms for 1000 lookups
EXPECT_LT(duration.count(), 1);
}
TEST_F(PokemonTableTest, Validation) {
EXPECT_TRUE(g_pokemonTable->validate());
}
TEST_F(PokemonTableTest, MewtwoStats) {
const auto* mewtwo = g_pokemonTable->getPokemon(150);
ASSERT_TRUE(mewtwo != nullptr);
EXPECT_EQ(mewtwo->id, 150);
EXPECT_EQ(mewtwo->name, "mewtwo");
EXPECT_EQ(mewtwo->base_stats.hp, 106);
EXPECT_EQ(mewtwo->base_stats.attack, 110);
EXPECT_EQ(mewtwo->base_stats.defense, 90);
EXPECT_EQ(mewtwo->base_stats.sp_attack, 154);
EXPECT_EQ(mewtwo->base_stats.sp_defense, 90);
EXPECT_EQ(mewtwo->base_stats.speed, 130);
EXPECT_EQ(mewtwo->types.getPrimary(), Type::PSYCHIC);
EXPECT_EQ(mewtwo->types.getSecondary(), Type::NONE);
}

View File

@@ -0,0 +1,171 @@
#include <gtest/gtest.h>
#include "core/stats.h"
namespace PokEng {
// Test fixture for stats tests
class StatsTest : public ::testing::Test {
protected:
void SetUp() override {
// Set up test fixtures
}
void TearDown() override {
// Clean up test fixtures
}
};
// Generation I && II example
// HP Attack Defense Sp.Atk Sp.Def Speed
// Base stat 35 55 30 50 50 90
// IV 14 16 26 18 10 0
// StatXP 22850 23140 17280 19625 24795 0
// Total 189 137 101 128 112 190
/**
// Test type string conversion
TEST_F(StatsTest, CalculateHP_GenI_II) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 35;
pikachuParams.m_iv = 14;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::HP;
pikachuParams.m_statExp = 22850;
EXPECT_EQ(CalculateHP<Generation::I>(pikachuParams), 189);
}
TEST_F(StatsTest, CalculateStat_GenI_II_Attack) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 55;
pikachuParams.m_iv = 16;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::ATTACK;
pikachuParams.m_statExp = 23140;
EXPECT_EQ(CalculateStat<Generation::I>(pikachuParams), 137);
}
TEST_F(StatsTest, CalculateStat_GenI_II_Defense) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 30;
pikachuParams.m_iv = 26;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::DEFENSE;
pikachuParams.m_statExp = 17280;
EXPECT_EQ(CalculateStat<Generation::I>(pikachuParams), 101);
}
TEST_F(StatsTest, CalculateStat_GenI_II_SpAttack) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 50;
pikachuParams.m_iv = 18;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::SP_ATTACK;
pikachuParams.m_statExp = 19625;
EXPECT_EQ(CalculateStat<Generation::I>(pikachuParams), 128);
}
TEST_F(StatsTest, CalculateStat_GenI_II_SpDefense) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 50;
pikachuParams.m_iv = 10;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::SP_DEFENSE;
pikachuParams.m_statExp = 24795;
EXPECT_EQ(CalculateStat<Generation::I>(pikachuParams), 112);
}
TEST_F(StatsTest, CalculateStat_GenI_II_Speed) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 90;
pikachuParams.m_iv = 0;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::SPEED;
pikachuParams.m_statExp = 0;
EXPECT_EQ(CalculateStat<Generation::I>(pikachuParams), 190);
}
// Generation 3+ example
// HP Attack Defense Sp.Atk Sp.Def Speed
// Base stat 108 130 95 80 85 102
// IV 24 12 30 16 23 5
// EV 74 190 91 48 84 23
// Total 289 278 193 135 171 171
TEST_F(StatsTest, CalculateStat_GenIII) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 108;
pikachuParams.m_iv = 24;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::ATTACK;
pikachuParams.m_statExp = 74;
EXPECT_EQ(CalculateStat<Generation::III>(pikachuParams), 278);
}
TEST_F(StatsTest, CalculateStat_GenIII_Defense) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 130;
pikachuParams.m_iv = 12;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::DEFENSE;
pikachuParams.m_statExp = 190;
EXPECT_EQ(CalculateStat<Generation::III>(pikachuParams), 193);
}
TEST_F(StatsTest, CalculateStat_GenIII_SpAttack) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 80;
pikachuParams.m_iv = 16;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::SP_ATTACK;
pikachuParams.m_statExp = 48;
EXPECT_EQ(CalculateStat<Generation::III>(pikachuParams), 135);
}
TEST_F(StatsTest, CalculateStat_GenIII_SpDefense) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 85;
pikachuParams.m_iv = 23;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::SP_DEFENSE;
pikachuParams.m_statExp = 84;
EXPECT_EQ(CalculateStat<Generation::III>(pikachuParams), 171);
}
TEST_F(StatsTest, CalculateStat_GenIII_Speed) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 102;
pikachuParams.m_iv = 5;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::SPEED;
pikachuParams.m_statExp = 23;
EXPECT_EQ(CalculateStat<Generation::III>(pikachuParams), 171);
}
TEST_F(StatsTest, CalculateHP_GenIII) {
StatCalculatorParams pikachuParams;
pikachuParams.m_base = 108;
pikachuParams.m_iv = 24;
pikachuParams.m_level = 81;
pikachuParams.m_statIndex = StatIndex::HP;
pikachuParams.m_statExp = 74;
EXPECT_EQ(CalculateHP<Generation::III>(pikachuParams), 289);
}
*/
} // namespace PokEng

View File

@@ -1,272 +0,0 @@
#include <gtest/gtest.h>
#include "pokemon_battle_sim.h"
#include <vector>
#include <tuple>
namespace PokEng {
// Test fixture for type system tests
class TypeSystemTest : public ::testing::Test {
protected:
void SetUp() override {
// Set up test fixtures
}
void TearDown() override {
// Clean up test fixtures
}
};
// Test type string conversion
TEST_F(TypeSystemTest, StringToTypeConversion) {
// Test valid conversions
EXPECT_EQ(TypeUtils::stringToType("fire"), Type::FIRE);
EXPECT_EQ(TypeUtils::stringToType("WATER"), Type::WATER); // Case insensitive
EXPECT_EQ(TypeUtils::stringToType("Normal"), Type::NORMAL);
EXPECT_EQ(TypeUtils::stringToType("none"), Type::NONE);
// Test invalid conversions
EXPECT_FALSE(TypeUtils::stringToType("invalid_type").has_value());
EXPECT_FALSE(TypeUtils::stringToType("").has_value());
}
TEST_F(TypeSystemTest, TypeToStringConversion) {
// Test valid conversions
EXPECT_EQ(TypeUtils::typeToString(Type::FIRE), "fire");
EXPECT_EQ(TypeUtils::typeToString(Type::WATER), "water");
EXPECT_EQ(TypeUtils::typeToString(Type::NONE), "none");
EXPECT_EQ(TypeUtils::typeToString(Type::DARK), "dark");
EXPECT_EQ(TypeUtils::typeToString(Type::FAIRY), "fairy");
// Test out of range (shouldn't happen in practice but good to test)
EXPECT_EQ(TypeUtils::typeToString(static_cast<Type>(static_cast<uint8_t>(Type::TYPE_COUNT) + 10)), "unknown");
}
// Test PokemonTypes class
TEST_F(TypeSystemTest, PokemonTypesBasic) {
// Single type Pokemon
PokemonTypes charizard(Type::FIRE);
EXPECT_EQ(charizard.getPrimary(), Type::FIRE);
EXPECT_EQ(charizard.getSecondary(), Type::NONE);
EXPECT_FALSE(charizard.hasSecondary());
// Dual type Pokemon
PokemonTypes arcanine(Type::FIRE, Type::NORMAL);
EXPECT_EQ(arcanine.getPrimary(), Type::FIRE);
EXPECT_EQ(arcanine.getSecondary(), Type::NORMAL);
EXPECT_TRUE(arcanine.hasSecondary());
}
TEST_F(TypeSystemTest, PokemonTypesModification) {
PokemonTypes pokemon;
// Test default state
EXPECT_EQ(pokemon.getPrimary(), Type::NONE);
EXPECT_EQ(pokemon.getSecondary(), Type::NONE);
// Test setting types
pokemon.setPrimary(Type::WATER);
pokemon.setSecondary(Type::FLYING);
EXPECT_EQ(pokemon.getPrimary(), Type::WATER);
EXPECT_EQ(pokemon.getSecondary(), Type::FLYING);
EXPECT_TRUE(pokemon.hasSecondary());
}
// Test type effectiveness for Generation 1
TEST_F(TypeSystemTest, TypeEffectivenessGen1) {
// Test some well-known type matchups from Generation 1
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::WATER, Type::FIRE), TypeMultiplier::DOUBLE);
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIRE, Type::WATER), TypeMultiplier::HALF);
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::NORMAL, Type::ROCK), TypeMultiplier::HALF);
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::ELECTRIC, Type::GROUND), TypeMultiplier::ZERO);
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIGHTING, Type::GHOST), TypeMultiplier::ZERO);
}
TEST_F(TypeSystemTest, TypeEffectivenessNeutral) {
// Test neutral effectiveness (1x damage)
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::NORMAL, Type::NORMAL), TypeMultiplier::NEUTRAL);
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIRE, Type::FIRE), TypeMultiplier::NEUTRAL);
// Test NONE types
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::NONE, Type::FIRE), TypeMultiplier::NEUTRAL);
EXPECT_EQ(TypeUtils::getTypeEffectiveness<Generation::I>(Type::FIRE, Type::NONE), TypeMultiplier::NEUTRAL);
}
// Test damage multiplier calculations
TEST_F(TypeSystemTest, DamageMultiplierSingleType) {
// Single type Pokemon
PokemonTypes charizard(Type::FIRE);
// Fire attack on Fire type (1.0x - same type is neutral)
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::FIRE, charizard);
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::NEUTRAL));
// Water attack on Fire type (2x)
multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::WATER, charizard);
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::DOUBLE));
}
TEST_F(TypeSystemTest, DamageMultiplierDualType) {
// Dual type Pokemon (Water/Flying)
PokemonTypes gyarados(Type::WATER, Type::FLYING);
// Electric attack on Water/Flying (2x * 2x = 4x)
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::ELECTRIC, gyarados);
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::QUADRUPLE));
// Grass attack on Water/Flying (0.5x * 0.5x = 0.25x)
multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::GRASS, gyarados);
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::QUARTER));
}
TEST_F(TypeSystemTest, DamageMultiplierNoneAttack) {
PokemonTypes charizard(Type::FIRE);
// NONE attack type should always return neutral multiplier
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::NONE, charizard);
EXPECT_EQ(multiplier, static_cast<uint32_t>(TypeMultiplier::NEUTRAL));
}
// Test the high-level damage calculation function
TEST_F(TypeSystemTest, CalculateDamage) {
PokemonTypes charizard(Type::FIRE);
const uint32_t baseDamage = 100;
// Fire attack on Fire type: 100 * 1.0 = 100 (same type is neutral)
uint32_t damage = calculateDamage<Generation::I>(baseDamage, Type::FIRE, charizard);
EXPECT_EQ(damage, 100);
// Water attack on Fire type: 100 * 2 = 200
damage = calculateDamage<Generation::I>(baseDamage, Type::WATER, charizard);
EXPECT_EQ(damage, 200);
// Normal attack on Fire type: 100 * 1 = 100
damage = calculateDamage<Generation::I>(baseDamage, Type::NORMAL, charizard);
EXPECT_EQ(damage, 100);
}
TEST_F(TypeSystemTest, CalculateDamageDualType) {
PokemonTypes gyarados(Type::WATER, Type::FLYING);
const uint32_t baseDamage = 100;
// Electric attack on Water/Flying: 100 * 4 = 400
uint32_t damage = calculateDamage<Generation::I>(baseDamage, Type::ELECTRIC, gyarados);
EXPECT_EQ(damage, 400);
// Grass attack on Water/Flying: 100 * 0.25 = 25
damage = calculateDamage<Generation::I>(baseDamage, Type::GRASS, gyarados);
EXPECT_EQ(damage, 25);
}
// Test edge cases
TEST_F(TypeSystemTest, EdgeCases) {
// Test with zero base damage
PokemonTypes pokemon(Type::FIRE);
uint32_t damage = calculateDamage<Generation::I>(0, Type::WATER, pokemon);
EXPECT_EQ(damage, 0);
// Test immunity (0x multiplier)
damage = calculateDamage<Generation::I>(100, Type::GROUND, PokemonTypes(Type::ELECTRIC));
EXPECT_EQ(damage, 0);
}
// Test different generations have different type charts
TEST_F(TypeSystemTest, GenerationDifferences) {
// Ghost/Fighting immunity in Gen 1
uint32_t gen1Multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(
Type::FIGHTING, PokemonTypes(Type::GHOST));
EXPECT_EQ(gen1Multiplier, static_cast<uint32_t>(TypeMultiplier::ZERO));
// In later generations, this might be different (Normal/Fighting would be neutral)
// Note: This is just a demonstration - we'd need actual Gen 2+ data to test properly
}
// Parameterized test for various type combinations
class TypeCombinationTest : public ::testing::TestWithParam<std::tuple<Type, Type, uint32_t>> {
};
TEST_P(TypeCombinationTest, VariousTypeCombinations) {
auto [attackType, defendType, expectedMultiplier] = GetParam();
PokemonTypes defender(defendType);
uint32_t actualMultiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(attackType, defender);
EXPECT_EQ(actualMultiplier, expectedMultiplier)
<< "Attack: " << TypeUtils::typeToString(attackType)
<< ", Defense: " << TypeUtils::typeToString(defendType);
}
INSTANTIATE_TEST_SUITE_P(
TypeCombinations,
TypeCombinationTest,
::testing::Values(
std::make_tuple(Type::WATER, Type::FIRE, static_cast<uint32_t>(TypeMultiplier::DOUBLE)),
std::make_tuple(Type::FIRE, Type::WATER, static_cast<uint32_t>(TypeMultiplier::HALF)),
std::make_tuple(Type::NORMAL, Type::ROCK, static_cast<uint32_t>(TypeMultiplier::HALF)),
std::make_tuple(Type::ELECTRIC, Type::GROUND, static_cast<uint32_t>(TypeMultiplier::ZERO)),
std::make_tuple(Type::NORMAL, Type::NORMAL, static_cast<uint32_t>(TypeMultiplier::NEUTRAL))
)
);
// Performance test to ensure type lookups are fast
TEST_F(TypeSystemTest, PerformanceTest) {
PokemonTypes pokemon(Type::FIRE, Type::FLYING);
// Test that multiple lookups are fast (this would be caught by benchmark tests too)
for (int i = 0; i < 1000; ++i) {
uint32_t multiplier = TypeUtils::calculateDamageMultiplier<Generation::I>(Type::WATER, pokemon);
(void)multiplier; // Prevent optimization
}
}
// Test the high-level damage calculation functions
TEST_F(TypeSystemTest, CalculateDamageFunctions) {
// Test calculateTypeDamage with single type
uint32_t damage1 = calculateTypeDamage<Generation::I>(100, Type::WATER, Type::FIRE);
EXPECT_EQ(damage1, 200);
uint32_t damage2 = calculateTypeDamage<Generation::I>(100, Type::FIRE, Type::WATER);
EXPECT_EQ(damage2, 50);
// Test calculateTypeDamage with dual type
uint32_t damage3 = calculateTypeDamage<Generation::I>(100, Type::ELECTRIC, Type::WATER, Type::FLYING);
EXPECT_EQ(damage3, 400);
// Test immunity
uint32_t damage4 = calculateTypeDamage<Generation::I>(100, Type::GROUND, Type::ELECTRIC);
EXPECT_EQ(damage4, 0);
}
// Test Pokemon damage calculation methods
TEST_F(TypeSystemTest, PokemonDamageCalculation) {
Pokemon charizard(6, 100, Type::FIRE, Type::FLYING);
// Test various attack types
uint32_t fireDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::FIRE);
EXPECT_EQ(fireDamage, 100); // Fire vs Fire/Flying: 1.0x (neutral for Fire) * 1.0x (neutral for Flying)
uint32_t waterDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::WATER);
EXPECT_EQ(waterDamage, 200);
uint32_t electricDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::ELECTRIC);
EXPECT_EQ(electricDamage, 200); // 2x vs Flying, neutral vs Fire
uint32_t groundDamage = charizard.calculateDamageTaken<Generation::I>(100, Type::GROUND);
EXPECT_EQ(groundDamage, 0); // Ground is immune to Flying
}
// Test generation differences
TEST_F(TypeSystemTest, GenerationDifferencesTest) {
// Steel type was introduced in Gen 2
uint32_t gen1Damage = calculateTypeDamage<Generation::I>(100, Type::NORMAL, Type::STEEL);
uint32_t gen8Damage = calculateTypeDamage<Generation::VIII>(100, Type::NORMAL, Type::STEEL);
// Results may differ based on loaded type charts
EXPECT_GE(gen1Damage, 0);
EXPECT_GE(gen8Damage, 0);
EXPECT_LE(gen1Damage, 400);
EXPECT_LE(gen8Damage, 400);
}
} // namespace PokEng

View File

@@ -634,7 +634,7 @@ private:
BaseAllocator baseAllocator_;
};
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++17
#if !RAPIDJSON_HAS_CXX17 // std::allocator<void> deprecated in C++20
template <typename BaseAllocator>
class StdAllocator<void, BaseAllocator> :
public std::allocator<void>

View File

@@ -643,7 +643,7 @@ RAPIDJSON_NAMESPACE_END
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
///////////////////////////////////////////////////////////////////////////////
// C++17 features
// C++20 features
#ifndef RAPIDJSON_HAS_CXX17
#define RAPIDJSON_HAS_CXX17 (RAPIDJSON_CPLUSPLUS >= 201703L)

View File

@@ -1,305 +1,208 @@
# Pokemon Data Downloader
# Pokemon Data Tools
A comprehensive tool for downloading Pokemon battle data from the PokeAPI using the `pokebase` library. This tool supports segmented downloading, data validation, and exports data in JSON format optimized for the C++ Pokemon battle simulator.
This directory contains tools for downloading and processing Pokemon data from the PokeAPI.
## Features
## Pokemon Downloader (`pokemon_downloader.py`)
- **Segmented Downloads**: Download specific ranges of Pokemon or moves for testing and incremental data collection
- **Concurrent Processing**: Multi-threaded downloads with configurable worker counts
- **Data Validation**: Built-in JSON schema validation for data integrity
- **Rate Limiting**: Respectful API usage with automatic rate limiting
- **Progress Tracking**: Beautiful progress bars and detailed logging
- **Battle-Ready Data**: Exports complete Pokemon stats, moves, types, and effectiveness data
- **CLI Interface**: Easy-to-use command-line interface with multiple commands
A comprehensive tool for downloading generation-specific Pokemon data from the PokeAPI.
## Installation
### Features
1. Install dependencies:
```bash
cd /testbed
pip install -r tools/requirements.txt
```
- **Type Effectiveness**: Downloads type matchup charts for each generation
- **Pokemon Data**: Downloads Pokemon species data including stats, types, and abilities
- **Moves Data**: Downloads move information filtered by generation availability
- **Progress Tracking**: Uses progress bars and detailed logging
- **Error Handling**: Robust error handling with retry logic
- **Flexible Output**: Configurable output directory structure
2. The tool is ready to use! No additional setup required.
### Usage
## Quick Start
### Download a Small Set of Pokemon (Testing)
#### Basic Usage
```bash
# Download first 5 Pokemon with their moves
python -m tools.data.pokemon_downloader download-pokemon --start 1 --end 5 --include-moves
# Download all data for all generations
python pokemon_downloader.py --all-generations --all-data-types
# Download specific Pokemon (Pikachu)
python -m tools.data.pokemon_downloader download-pokemon --start 25 --end 25 --include-moves
# Download specific generations and data types
python pokemon_downloader.py --generations generation-i,generation-ii --data-types types,pokemon
# Download only type effectiveness for Generation I
python pokemon_downloader.py --generations generation-i --data-types types
```
### Download Specific Moves
#### Command Line Options
- `--generations`: Comma-separated list of generations (generation-i, generation-ii, etc.)
- `--all-generations`: Download data for all available generations
- `--data-types`: Comma-separated list of data types (types, pokemon, moves)
- `--all-data-types`: Download all data types
- `--output-dir`: Output directory (default: data)
#### Examples
```bash
# Download first 10 moves
python -m tools.data.pokemon_downloader download-moves --move-ids "1,2,3,4,5,6,7,8,9,10"
# Download Pokemon and moves for Generation I and II
python tools/data/pokemon_downloader.py \
--generations generation-i,generation-ii \
--data-types pokemon,moves \
--output-dir data
# Download all type effectiveness data
python tools/data/pokemon_downloader.py \
--all-generations \
--data-types types
```
### Download Type Effectiveness Data
### Output Structure
```bash
# Download complete type effectiveness chart
python -m tools.data.pokemon_downloader download-types
The tool creates the following directory structure:
```
data/
├── types/
│ ├── generation-i.json
│ ├── generation-ii.json
│ └── ...
├── pokemon/
│ ├── generation-i.json
│ ├── generation-ii.json
│ └── ...
└── moves/
├── generation-i.json
├── generation-ii.json
└── ...
```
### Download Complete Gen 1 Dataset
### Data Formats
```bash
# Download all Gen 1 Pokemon (1-151) with moves and type data
python -m tools.data.pokemon_downloader download-complete --start 1 --end 151
```
## CLI Commands
### Global Options
- `--output-dir`: Directory to save downloaded data (default: `data`)
- `--cache-dir`: Directory for API response caching (default: `.cache`)
- `--no-validation`: Disable data validation before saving
### Commands
#### `download-pokemon`
Download Pokemon data for a specific ID range.
```bash
python -m tools.data.pokemon_downloader download-pokemon [OPTIONS]
```
Options:
- `--start`: Starting Pokemon ID (default: 1)
- `--end`: Ending Pokemon ID (default: 10)
- `--workers`: Number of concurrent workers (default: 5)
- `--include-moves`: Also download moves for these Pokemon
#### `download-moves`
Download specific moves by ID.
```bash
python -m tools.data.pokemon_downloader download-moves --move-ids "1,2,3,4,5"
```
Options:
- `--move-ids`: Comma-separated list of move IDs
- `--workers`: Number of concurrent workers (default: 5)
#### `download-types`
Download type effectiveness data.
```bash
python -m tools.data.pokemon_downloader download-types
```
#### `download-complete`
Download complete dataset (Pokemon, moves, and type effectiveness).
```bash
python -m tools.data.pokemon_downloader download-complete [OPTIONS]
```
Options:
- `--start`: Starting Pokemon ID (default: 1)
- `--end`: Ending Pokemon ID (default: 151 for Gen 1)
- `--workers`: Number of concurrent workers (default: 5)
## Data Structure
### Pokemon Data Format
#### Type Effectiveness (`types/generation-X.json`)
```json
{
"1": {
"id": 1,
"name": "bulbasaur",
"types": ["grass", "poison"],
"base_stats": {
"hp": 45,
"attack": 49,
"defense": 49,
"special_attack": 65,
"special_defense": 65,
"speed": 45
},
"abilities": ["overgrow", "chlorophyll"],
"moves": [1, 2, 3, 4, ...],
"weight": 69,
"height": 7,
"base_experience": 64
"fire": {
"double_damage_from": ["water", "ground", "rock"],
"double_damage_to": ["grass", "ice", "bug", "steel"],
"half_damage_from": ["fire", "water", "rock", "dragon"],
"half_damage_to": ["fire", "water", "rock", "dragon"],
"no_damage_from": ["fire"],
"no_damage_to": ["fire"]
}
}
```
### Move Data Format
```json
{
"1": {
"id": 1,
"name": "pound",
"type": "normal",
"power": 40,
"accuracy": 100,
"pp": 35,
"priority": 0,
"damage_class": "physical",
"effect_id": null,
"effect_chance": null,
"target": "selected-pokemon",
"description": "Inflicts regular damage."
}
}
```
### Type Effectiveness Format
#### Pokemon Data (`pokemon/generation-X.json`)
```json
[
{
"attacking_type": "fire",
"defending_type": "grass",
"damage_factor": 2.0
},
{
"attacking_type": "water",
"defending_type": "fire",
"damage_factor": 2.0
"id": 1,
"name": "bulbasaur",
"types": ["grass", "poison"],
"stats": {
"hp": 45,
"attack": 49,
"defense": 49,
"special-attack": 65,
"special-defense": 65,
"speed": 45
},
"abilities": [...],
"species": {
"generation": "generation-i",
"is_legendary": false,
"is_mythical": false
}
}
]
```
## Examples
#### Moves Data (`moves/generation-X.json`)
### Basic Usage (Python API)
```python
from pathlib import Path
from tools.data.pokemon_downloader import PokemonDownloader
# Initialize downloader
downloader = PokemonDownloader(
output_dir=Path("my_pokemon_data"),
validate_data=True
)
# Download first 10 Pokemon
pokemon_data = downloader.download_pokemon_batch(1, 10)
downloader.save_pokemon_data(pokemon_data, "starter_pokemon.json")
# Download some moves
move_ids = [1, 2, 3, 4, 5] # Pound, Karate Chop, etc.
moves_data = downloader.download_moves_batch(move_ids)
downloader.save_moves_data(moves_data, "basic_moves.json")
# Download type effectiveness
effectiveness = downloader.download_type_effectiveness()
downloader.save_type_effectiveness(effectiveness, "types.json")
```json
[
{
"id": 1,
"name": "pound",
"power": 40,
"pp": 35,
"accuracy": 100,
"type": "normal",
"damage_class": "physical",
"generation": "generation-i"
}
]
```
### Testing Small Segments
### Dependencies
```python
# Test with just 3 Pokemon
python tools/data/test_downloader.py
The tool requires the following Python packages (available in `tools/requirements.txt`):
- `requests` - HTTP requests to PokeAPI
- `tqdm` - Progress bars
- `argparse` - Command line argument parsing (built-in)
### API Rate Limiting
The tool includes:
- Retry logic with exponential backoff
- Respectful request timing
- User-agent identification
- Error handling for rate limits
### New Features (Latest Update)
**Efficient Moves Download:**
- Downloads all moves once and saves to `data/all_moves.json`
- Subsequent generations filter from this master file instead of re-downloading
- Dramatically reduces API calls and download time
**Smart Caching:**
- Checks if data files already exist and contain expected amount of data
- Skips re-downloading if files are present and valid
- Supports partial downloads (e.g., if some Pokemon are missing, only downloads missing ones)
**File Structure:**
```
data/
├── all_moves.json # Complete moves database (all generations)
├── types/
│ ├── generation-i.json # Type effectiveness for each generation
│ ├── generation-ii.json
│ └── ...
├── pokemon/
│ ├── generation-i.json # Pokemon data for each generation
│ ├── generation-ii.json
│ └── ...
└── moves/
├── generation-i.json # Moves available in each generation
├── generation-ii.json # (filtered from all_moves.json)
└── ...
```
### Custom Data Validation
### Performance Improvements
```python
from tools.data.schemas import DataValidator
- **Moves**: Downloads all 900+ moves once, then filters per generation
- **Caching**: Checks file existence and validity before downloading
- **Batch Processing**: Downloads complete datasets efficiently
- **Resume Support**: Can continue interrupted downloads
validator = DataValidator()
### Usage Examples with Caching
# Validate Pokemon data
errors = validator.validate_pokemon_collection(pokemon_data)
if errors:
print("Validation errors:", errors)
```
## Performance Considerations
- **Rate Limiting**: The tool implements 100ms delays between API calls to be respectful
- **Concurrent Workers**: Default of 5 workers balances speed with API courtesy
- **Caching**: API responses are cached to avoid redundant requests
- **Memory Usage**: Large datasets are processed in batches to manage memory
## Recommended Usage Patterns
### For Development/Testing
```bash
# Start small - download just a few Pokemon
python -m tools.data.pokemon_downloader download-pokemon --start 1 --end 3 --include-moves
# First run - downloads all data
python tools/data/pokemon_downloader.py --all-generations --all-data-types
# Test specific Pokemon you're interested in
python -m tools.data.pokemon_downloader download-pokemon --start 25 --end 25 --include-moves # Pikachu
# Subsequent runs - uses cached data (much faster!)
python tools/data/pokemon_downloader.py --all-generations --all-data-types
# Only downloads missing data
python tools/data/pokemon_downloader.py --generations generation-v --data-types pokemon
```
### For Production Data
```bash
# Download by generations or batches
python -m tools.data.pokemon_downloader download-pokemon --start 1 --end 50 --include-moves
python -m tools.data.pokemon_downloader download-pokemon --start 51 --end 100 --include-moves
python -m tools.data.pokemon_downloader download-pokemon --start 101 --end 151 --include-moves
### Notes
# Always download type effectiveness data
python -m tools.data.pokemon_downloader download-types
```
### For Complete Gen 1 Dataset
```bash
# One command for everything (will take several minutes)
python -m tools.data.pokemon_downloader download-complete --start 1 --end 151
```
## Data Validation
The tool includes comprehensive JSON schema validation:
- **Pokemon Data**: Validates stats, types, abilities, and structure
- **Move Data**: Validates power, accuracy, PP, and damage classes
- **Type Effectiveness**: Validates damage multipliers and type names
- **Generation 1 Focus**: Ensures only valid Gen 1 types and data
Validation errors are displayed during save operations but don't prevent saving (warnings only).
## Integration with C++ Battle Simulator
The exported JSON files are designed to be easily consumed by the C++ battle simulator:
1. **Pokemon Data**: Direct mapping to Pokemon class properties
2. **Move Data**: Complete move information for battle calculations
3. **Type Effectiveness**: Lookup table for damage calculations
4. **Consistent IDs**: All data uses consistent Pokemon and move IDs
## Troubleshooting
### Common Issues
1. **Network Errors**: The tool retries failed requests automatically
2. **Rate Limiting**: Built-in delays prevent API rate limiting
3. **Memory Usage**: Large downloads are processed in batches
4. **Validation Warnings**: Usually safe to ignore, indicate minor data inconsistencies
### Getting Help
- Run tests: `python tools/data/test_downloader.py`
- Check logs: The tool provides detailed logging for debugging
- Validate data: Use `--no-validation` flag if validation is too strict
## Contributing
To extend the downloader:
1. Add new data structures to `pokemon_downloader.py`
2. Update validation schemas in `schemas.py`
3. Add tests to `test_downloader.py`
4. Update this documentation
## License
This tool is part of the Pokemon Battle Simulator project and follows the same license terms.
- Some Pokemon and moves appear in multiple generations
- Type effectiveness is consistent across generations in the base game
- The tool respects the PokeAPI fair use policy
- Data is cached locally to avoid repeated API calls
- `all_moves.json` contains the complete moves database for efficient filtering

View File

@@ -1,228 +1,94 @@
#!/usr/bin/env python3
"""
Example usage of the Pokemon Data Downloader.
Example usage of the Pokemon Data Downloader
This script demonstrates various ways to use the Pokemon downloader
for different scenarios and use cases.
This script demonstrates how to use the pokemon_downloader.py tool
to download different types of Pokemon data from the PokeAPI.
"""
import subprocess
import sys
from pathlib import Path
# Add the tools directory to Python path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
def run_command(cmd, description):
"""Run a command and print the description."""
print(f"\n{'='*60}")
print(f"Running: {description}")
print(f"Command: {' '.join(cmd)}")
print(f"{'='*60}")
from data.pokemon_downloader import PokemonDownloader
from data.schemas import DataValidator
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
console = Console()
def example_basic_download():
"""Example 1: Basic Pokemon download."""
console.print(Panel.fit("Example 1: Basic Pokemon Download", style="bold blue"))
# Create downloader with custom output directory
downloader = PokemonDownloader(output_dir=Path("example_data"))
# Download first 3 Pokemon (Bulbasaur, Ivysaur, Venusaur)
console.print("Downloading first 3 Pokemon...")
pokemon_data = downloader.download_pokemon_batch(1, 3, max_workers=2)
if pokemon_data:
# Save to file
downloader.save_pokemon_data(pokemon_data, "starter_pokemon.json")
# Display summary
table = downloader.get_stats_summary(pokemon_data)
console.print(table)
console.print("✅ Basic download complete!\n")
def example_moves_download():
"""Example 2: Download specific moves."""
console.print(Panel.fit("Example 2: Download Specific Moves", style="bold blue"))
downloader = PokemonDownloader(output_dir=Path("example_data"))
# Download some classic moves
classic_moves = [1, 2, 33, 34, 36] # Pound, Karate Chop, Tackle, Body Slam, Take Down
console.print(f"Downloading {len(classic_moves)} classic moves...")
moves_data = downloader.download_moves_batch(classic_moves, max_workers=3)
if moves_data:
downloader.save_moves_data(moves_data, "classic_moves.json")
# Show move details
table = Table(title="Downloaded Moves")
table.add_column("Name", style="cyan")
table.add_column("Type", style="green")
table.add_column("Power", style="magenta")
table.add_column("Accuracy", style="yellow")
for move in moves_data.values():
power_str = str(move.power) if move.power else ""
accuracy_str = str(move.accuracy) if move.accuracy else ""
table.add_row(
move.name.title(),
move.type.title(),
power_str,
accuracy_str
)
console.print(table)
console.print("✅ Moves download complete!\n")
def example_validation():
"""Example 3: Data validation."""
console.print(Panel.fit("Example 3: Data Validation", style="bold blue"))
validator = DataValidator()
# Create sample Pokemon data for validation
sample_pokemon = {
"25": { # Pikachu
"id": 25,
"name": "pikachu",
"types": ["electric"],
"base_stats": {
"hp": 35,
"attack": 55,
"defense": 40,
"special_attack": 50,
"special_defense": 50,
"speed": 90
},
"abilities": ["static", "lightning-rod"],
"moves": [1, 2, 3, 4, 5],
"weight": 60,
"height": 4,
"base_experience": 112
}
}
# Validate the data
errors = validator.validate_pokemon_collection(sample_pokemon)
if errors:
console.print(f"❌ Validation found {len(errors)} errors:")
for error in errors:
console.print(f" - {error}")
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("✓ Success!")
if result.stdout:
print("Output:", result.stdout)
else:
console.print("✅ Sample Pokemon data is valid!")
console.print("✅ Validation example complete!\n")
def example_type_effectiveness():
"""Example 4: Download type effectiveness data."""
console.print(Panel.fit("Example 4: Type Effectiveness", style="bold blue"))
downloader = PokemonDownloader(output_dir=Path("example_data"))
console.print("Downloading type effectiveness data...")
effectiveness_data = downloader.download_type_effectiveness()
if effectiveness_data:
downloader.save_type_effectiveness(effectiveness_data, "type_chart.json")
# Show some interesting type matchups
table = Table(title="Sample Type Effectiveness")
table.add_column("Attacking Type", style="cyan")
table.add_column("Defending Type", style="green")
table.add_column("Effectiveness", style="magenta")
# Show super effective matchups
super_effective = [e for e in effectiveness_data if e.damage_factor == 2.0][:5]
for entry in super_effective:
table.add_row(
entry.attacking_type.title(),
entry.defending_type.title(),
"Super Effective (2x)"
)
console.print(table)
console.print(f"Total effectiveness entries: {len(effectiveness_data)}")
console.print("✅ Type effectiveness download complete!\n")
def example_integrated_workflow():
"""Example 5: Integrated workflow - Pokemon with their moves."""
console.print(Panel.fit("Example 5: Integrated Workflow", style="bold blue"))
downloader = PokemonDownloader(output_dir=Path("example_data"))
# Download a specific Pokemon (Charizard)
console.print("Downloading Charizard (ID: 6)...")
pokemon_data = downloader.download_pokemon_batch(6, 6, max_workers=1)
if pokemon_data:
charizard = pokemon_data[6]
console.print(f"✅ Downloaded {charizard.name.title()}")
console.print(f" - Types: {', '.join(charizard.types)}")
console.print(f" - Base stats total: {sum(charizard.base_stats.__dict__.values())}")
console.print(f" - Can learn {len(charizard.moves)} moves")
# Download first 15 moves that Charizard can learn
charizard_moves = charizard.moves[:15]
console.print(f"\nDownloading {len(charizard_moves)} of Charizard's moves...")
moves_data = downloader.download_moves_batch(charizard_moves, max_workers=3)
if moves_data:
# Save both datasets
downloader.save_pokemon_data(pokemon_data, "charizard.json")
downloader.save_moves_data(moves_data, "charizard_moves.json")
# Show some moves
console.print("\nSample moves Charizard can learn:")
for move_id, move in list(moves_data.items())[:5]:
power_str = f"{move.power} power" if move.power else "status move"
console.print(f" - {move.name.title()} ({move.type} type, {power_str})")
console.print("✅ Integrated workflow complete!\n")
print("✗ Failed!")
if result.stderr:
print("Error:", result.stderr)
sys.exit(1)
def main():
"""Run all examples."""
console.print(Panel.fit(
"🔥 Pokemon Data Downloader Examples",
style="bold red"
))
console.print("This script demonstrates various usage patterns for the Pokemon downloader.\n")
# Run examples
try:
example_basic_download()
example_moves_download()
example_validation()
example_type_effectiveness()
example_integrated_workflow()
console.print(Panel.fit(
"🎉 All examples completed successfully!\n\n"
"Check the 'example_data' directory for downloaded files.\n"
"You can now use these patterns in your own projects.",
style="bold green"
))
except KeyboardInterrupt:
console.print("\n⚠️ Examples interrupted by user")
except Exception as e:
console.print(f"\n❌ Error running examples: {e}")
return 1
return 0
"""Demonstrate various usage examples of the Pokemon downloader."""
print("Pokemon Data Downloader - Usage Examples")
print("=========================================")
# Ensure we're in the right directory
if not Path("tools/data/pokemon_downloader.py").exists():
print("Error: Please run this script from the project root directory")
sys.exit(1)
# Example 1: Download type effectiveness for Generation I
run_command([
"python", "tools/data/pokemon_downloader.py",
"--generations", "generation-i",
"--data-types", "types"
], "Download type effectiveness for Generation I")
# Example 2: Download Pokemon data for multiple generations
run_command([
"python", "tools/data/pokemon_downloader.py",
"--generations", "generation-i,generation-ii",
"--data-types", "pokemon"
], "Download Pokemon data for Generations I and II")
# Example 3: Download moves data for Generation I
run_command([
"python", "tools/data/pokemon_downloader.py",
"--generations", "generation-i",
"--data-types", "moves"
], "Download moves data for Generation I")
# Example 4: Download all data types for one generation
run_command([
"python", "tools/data/pokemon_downloader.py",
"--generations", "generation-i",
"--all-data-types"
], "Download all data types for Generation I")
# Example 5: Download specific data to custom directory
custom_dir = "my_pokemon_data"
run_command([
"python", "tools/data/pokemon_downloader.py",
"--generations", "generation-i",
"--data-types", "types",
"--output-dir", custom_dir
], f"Download type data to custom directory: {custom_dir}")
# Show help
print(f"\n{'='*60}")
print("Available command line options:")
print(f"{'='*60}")
subprocess.run([
"python", "tools/data/pokemon_downloader.py", "--help"
])
print(f"\n{'='*60}")
print("Examples completed successfully!")
print("Check the 'data' directory for downloaded files.")
print(f"{'='*60}")
if __name__ == "__main__":
sys.exit(main())
main()

1128
tools/data/pokemon_downloader.py Normal file → Executable file

File diff suppressed because it is too large Load Diff