Skip to content

Commit 5121759

Browse files
authored
Merge pull request #13 from cpp-gamedev/issue-9
Issue 9
2 parents 5b37935 + 46dc806 commit 5121759

File tree

14 files changed

+258
-201
lines changed

14 files changed

+258
-201
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,4 +368,9 @@ venv/
368368

369369
# project-specific files and directories
370370
assets/
371-
manifest.json
371+
manifest.json
372+
373+
# VSCode, clangd etc
374+
.vscode/
375+
.cache/
376+
compile_commands.json

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "libs/djson"]
2+
path = libs/djson
3+
url = https://github.com/karnkaul/djson
4+
[submodule "libs/include/str_format"]
5+
path = libs/include/str_format
6+
url = https://github.com/karnkaul/str-format

CMakeLists.txt

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,46 @@
11
cmake_minimum_required(VERSION 3.18 FATAL_ERROR)
22

3+
function(update_git_submodules MSG_TYPE)
4+
message(STATUS "Updating git submodules...")
5+
execute_process(COMMAND ${GIT_EXECUTABLE} submodule update --init --recursive
6+
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
7+
RESULT_VARIABLE UPDATE_SUBMODULES_RESULT
8+
)
9+
if(NOT UPDATE_SUBMODULES_RESULT EQUAL "0")
10+
message(${MSG_TYPE} "git submodule update failed!")
11+
endif()
12+
endfunction()
13+
314
set(CMAKE_CXX_STANDARD 17)
415
set(CMAKE_CXX_STANDARD_REQUIRED ON)
516
set(CMAKE_CXX_EXTENSIONS OFF)
617
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "")
718
set(APP_VERSION "1.0.0" CACHE STRING "Application Version" FORCE)
819
project(pkmn VERSION ${APP_VERSION})
920

21+
find_package(Git QUIET)
22+
if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/.git")
23+
option(PKMN_GIT_UPDATE_SUBMODULES "Init/Update submodules during generation" ON)
24+
if(PKMN_GIT_UPDATE_SUBMODULES)
25+
update_git_submodules(FATAL_ERROR)
26+
endif()
27+
endif()
28+
1029
file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.*pp")
30+
31+
# Libraries
32+
add_subdirectory(libs/djson)
33+
1134
add_executable(${PROJECT_NAME} ${SOURCES})
35+
target_include_directories(${PROJECT_NAME} PRIVATE libs/include)
36+
37+
if(CMAKE_CXX_COMPILER_ID STREQUAL Clang OR CMAKE_CXX_COMPILER_ID STREQUAL GNU)
38+
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra $<$<NOT:$<CONFIG:Debug>>:-Werror>)
39+
endif()
1240

13-
if(W_MSBUILD)
41+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
42+
target_compile_options(${PROJECT_NAME} PRIVATE $<$<NOT:$<CONFIG:Debug>>:/WX>)
1443
set_property(DIRECTORY ${CMAKE_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
1544
endif()
1645

46+
target_link_libraries(${PROJECT_NAME} PUBLIC djson::djson)

README.md

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,32 +28,30 @@
2828
If this is your first time using a python script, use
2929

3030
```bash
31-
$ python -m venv venv/
32-
$ source venv/Scripts/activate
33-
$ python -m pip install --upgrade pip
34-
$ pip install -r requirements.txt --only-binary all
31+
python -m venv venv/
32+
source venv/Scripts/activate
33+
python -m pip install --upgrade pip
34+
pip install -r requirements.txt --only-binary all
3535
```
3636

3737
to install the dependencies in a virtual environment. Note that this script
38-
assumes that it is being run from the project's root directory. After that
39-
you should be able to use this script:
38+
assumes that it is being run from the project's root directory. You need to create
39+
at least two new pkmn file sets before you can start playing this game:
4040

4141
```bash
42-
$ # creates two new pkmn data sets (sprite + data)
43-
$ python gen_data.py --verbose make --id 1 4
44-
$ # create manifest.json
45-
$ python gen_data.py manifest
42+
# creates two new pkmns (bulbasaur and charmander)
43+
python gen_data.py --verbose make --id 1 4
44+
# creates a manifest.json
45+
python gen_data.py manifest
4646
```
4747

48-
You can also use the `--name` option for identifying a new pokemon. Repeat both
49-
steps - you need at least two pokemon to play this game. In case of doubt, use
48+
In case of doubt, use
5049

5150
```bash
52-
$ python gen_data.py --help
51+
python gen_data.py --help
5352
```
5453

55-
to get more help. Once you've obtained these files, build the project to play
56-
this game. Use the `--mirror` flag for your own pokemon (recommended).
54+
to get more help.
5755

5856
### On Visual Studio (Windows)
5957

gen_data.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,22 @@
55
66
Description
77
-----------
8-
This script uses the Pokemon API to create a JSON file for the pkmn game.
8+
This script uses the Pokemon API to create a JSON file and an ASCII sprite for the
9+
pkmn game. Run it from the root directory of the project and ensure that all dependencies
10+
are installed.
911
1012
Usage
1113
-----
12-
Run 'python gen_data.py make --name <pokemon>' from the project's root directory
13-
to create a new JSON file for pkmn. Append the '--help' option for more help.
1414
15-
Additionally, use `python gen_data.py ascii --name <pokemon>` to create a new
16-
ascii image. In both instances, a ID may be used as primary argument instead.
15+
1. creates two new pkmns (bulbasaur and charmander)
16+
>> python gen_data.py --verbose make --id 1 4
17+
18+
2. creates a manifest.json
19+
>> python gen_data.py manifest
1720
"""
1821

1922
import argparse
2023
import json
21-
import os
2224
from collections import Counter
2325
from pathlib import Path
2426
from pprint import pprint
@@ -29,7 +31,6 @@
2931
import colorama
3032
import requests
3133
from colorama import Fore, Style
32-
from colorama.ansi import clear_screen
3334
from PIL import Image, ImageOps
3435
from rich.console import Console
3536
from rich.progress import track
@@ -98,24 +99,23 @@ def req_pkmn_data(id_: int, verbose: bool) -> None:
9899
'id': response['id'],
99100
'name': response['name'],
100101
'level': level,
101-
'hp': int(2 * level * (0.8 + 0.4 * random())), # formula for hp is a rough estimation
102-
'atk': 1,
103-
'def': 1,
102+
'hp': int(2 * level * (0.8 + 0.4 * random())),
103+
'atk': 100,
104+
'def': 100,
104105
}
105106

106-
# the base api does not provide detailed information about moves,
107-
# so we need to make more calls to the api (+1 per move)
108107
moves = {}
109108
endpoints = [move['move']['url'] for move in response['moves']]
110109
for index, endpoint in track(enumerate(endpoints), "Sending Requests", total=len(endpoints), transient=True):
111110
move_response = requests.get(endpoint).json()
111+
unescape = lambda text: text.replace('\u00e9','e').replace('\u2019', "'").replace('\n',' ').replace('\u00ad', '-')
112112
moves[index] = {
113113
'name': move_response['names'][7]['name'],
114114
'accuracy': int(move_response['accuracy']) if move_response['accuracy'] is not None else None,
115-
'effect_changes': move_response['effect_changes'],
115+
'effect_changes': move_response['effect_changes'] if len(move_response['effect_changes']) > 0 else [None],
116116
'effect_chance': int(move_response['effect_chance']) if move_response['effect_chance'] is not None else None,
117117
'power': int(move_response['power']) if move_response['power'] is not None else None,
118-
'flavor_text_entries': [entry['flavor_text'] for entry in move_response['flavor_text_entries'] if entry['language']['name'] == 'en']
118+
'flavor_text_entries': [unescape(entry['flavor_text']) for entry in move_response['flavor_text_entries'] if entry['language']['name'] == 'en']
119119
}
120120
result['moves'] = moves
121121

libs/djson

Submodule djson added at 435e1bf

libs/include/str_format

Submodule str_format added at 123b3a8

src/anim.cpp

Lines changed: 50 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,65 @@
1+
#include <algorithm>
12
#include <filesystem>
23
#include <iostream>
34
#include <string>
45
#include <vector>
5-
#include "str_format.hpp"
6+
#include "models.hpp"
67
#include "utils.hpp"
8+
#include <str_format/str_format.hpp>
79

8-
// TODO: update args to Pokemon object
9-
std::vector<std::string> gen_healthbar(std::string name, int level, int hp, int max_hp)
10+
std::vector<std::string> gen_healthbar(Pokemon& pkmn)
1011
{
11-
/*
12-
* Bulbasaur :L30 // label
13-
* HP [********* ] // progressbar
14-
* 58 / 60 // hitpoints
15-
*/
16-
std::string label = kt::format_str("{} :L{}\n", name, level);
17-
18-
double percentage = ceil(static_cast<double>(hp) / max_hp * 100);
19-
int digits = static_cast<int>(log10(percentage));
20-
int first_digit = static_cast<int>(percentage / pow(10, digits));
21-
22-
std::string stars = std::string(first_digit, '*');
23-
stars = stars.append(std::string(10LL - first_digit, ' '));
24-
std::string progressbar = kt::format_str("HP [{}]\n", style(stars, Color::GREEN));
25-
26-
std::string hitpoints = kt::format_str("{} / {}\n", hp, max_hp);
27-
hitpoints = std::string(16 - hitpoints.length(), ' ').append(hitpoints);
12+
/*
13+
* bulbasaur :L30 // label
14+
* HP [********* ] // progressbar
15+
* 58 / 60 // hitpoints
16+
*/
17+
std::string label = kt::format_str("{} :L{}", pkmn.name, pkmn.level);
18+
std::size_t max_width = pkmn.name.length() > 10 ? label.length() : 15;
19+
20+
label = std::string(max_width - label.length(), ' ').append(label);
21+
22+
double linear_map = (10.0 / pkmn.max_hp) * pkmn.hp;
23+
int hp_scaled = (0 < linear_map && linear_map < 1) ? 1 : std::floor(linear_map);
24+
25+
std::string stars = std::string(hp_scaled, '*');
26+
stars = stars.append(std::string(10 - hp_scaled, ' '));
27+
Color star_color = (hp_scaled >= 5) ? Color::GREEN : (3 < hp_scaled && hp_scaled < 5) ? Color::YELLOW : Color::RED;
28+
std::string progressbar = kt::format_str("HP [{}]", style(stars, star_color));
29+
progressbar = std::string(max_width - 15, ' ').append(progressbar);
30+
31+
std::string hitpoints = kt::format_str("{} / {}", pkmn.hp, pkmn.max_hp);
32+
hitpoints = std::string(max_width - hitpoints.length(), ' ').append(hitpoints);
2833

2934
return {label, progressbar, hitpoints};
3035
}
3136

32-
std::vector<std::string> load_sprite(int id, const std::filesystem::path& assets)
37+
void print_frame(Pokemon& pkmn1, Pokemon& pkmn2)
3338
{
34-
for (const auto& file : std::filesystem::directory_iterator(assets))
39+
std::string healthbars{};
40+
std::string sprites{};
41+
42+
std::vector<std::string> healthbar1 = gen_healthbar(pkmn1);
43+
std::vector<std::string> healthbar2 = gen_healthbar(pkmn2);
44+
45+
std::size_t padding = healthbar1[0].length() + healthbar2[0].length();
46+
47+
if (padding > 30)
48+
padding -= 2 * (padding - 30);
49+
50+
for (std::size_t i = 0; i < 3; i++)
51+
healthbars.append(healthbar1[i]).append(std::string(padding, ' ')).append(healthbar2[i]).append("\n");
52+
53+
std::cout << healthbars;
54+
55+
for (std::size_t i = 0; i < 20; i++)
3556
{
36-
if (file.path().extension() == ".txt" && std::stoi(file.path().stem().string()) == id)
37-
{
38-
return read_file(file);
39-
}
57+
std::string tmp = pkmn1.sprite[i]; // strip new line
58+
tmp.erase(std::remove(tmp.begin(), tmp.end(), '\n'), tmp.end());
59+
sprites.append(tmp).append(std::string(20, ' ')).append(pkmn2.sprite[i]);
4060
}
61+
62+
std::cout << sprites;
63+
64+
return;
4165
}

src/anim.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
#include<string>
44
#include<vector>
5+
#include "models.hpp"
56

6-
std::vector<std::string> gen_healthbar(std::string name, int level, int hp, int max_hp);
7+
std::vector<std::string> gen_healthbar(Pokemon& pkmn);
78

8-
std::vector<std::string> load_sprite(int id, const std::filesystem::path& assets);
9+
void print_frame(Pokemon& pkmn1, Pokemon& pkmn2);

0 commit comments

Comments
 (0)