diff --git a/poetry.lock b/poetry.lock index 7b19f907..afaa9921 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1492,18 +1492,18 @@ files = [ [[package]] name = "pydantic" -version = "2.5.3" +version = "2.6.0" description = "Data validation using Python type hints" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic-2.5.3-py3-none-any.whl", hash = "sha256:d0caf5954bee831b6bfe7e338c32b9e30c85dfe080c843680783ac2b631673b4"}, - {file = "pydantic-2.5.3.tar.gz", hash = "sha256:b3ef57c62535b0941697cce638c08900d87fcb67e29cfa99e8a68f747f393f7a"}, + {file = "pydantic-2.6.0-py3-none-any.whl", hash = "sha256:1440966574e1b5b99cf75a13bec7b20e3512e8a61b894ae252f56275e2c465ae"}, + {file = "pydantic-2.6.0.tar.gz", hash = "sha256:ae887bd94eb404b09d86e4d12f93893bdca79d766e738528c6fa1c849f3c6bcf"}, ] [package.dependencies] annotated-types = ">=0.4.0" -pydantic-core = "2.14.6" +pydantic-core = "2.16.1" typing-extensions = ">=4.6.1" [package.extras] @@ -1511,116 +1511,90 @@ email = ["email-validator (>=2.0.0)"] [[package]] name = "pydantic-core" -version = "2.14.6" +version = "2.16.1" description = "" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:72f9a942d739f09cd42fffe5dc759928217649f070056f03c70df14f5770acf9"}, - {file = "pydantic_core-2.14.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6a31d98c0d69776c2576dda4b77b8e0c69ad08e8b539c25c7d0ca0dc19a50d6c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5aa90562bc079c6c290f0512b21768967f9968e4cfea84ea4ff5af5d917016e4"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:370ffecb5316ed23b667d99ce4debe53ea664b99cc37bfa2af47bc769056d534"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f85f3843bdb1fe80e8c206fe6eed7a1caeae897e496542cee499c374a85c6e08"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9862bf828112e19685b76ca499b379338fd4c5c269d897e218b2ae8fcb80139d"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:036137b5ad0cb0004c75b579445a1efccd072387a36c7f217bb8efd1afbe5245"}, - {file = "pydantic_core-2.14.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:92879bce89f91f4b2416eba4429c7b5ca22c45ef4a499c39f0c5c69257522c7c"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0c08de15d50fa190d577e8591f0329a643eeaed696d7771760295998aca6bc66"}, - {file = "pydantic_core-2.14.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:36099c69f6b14fc2c49d7996cbf4f87ec4f0e66d1c74aa05228583225a07b590"}, - {file = "pydantic_core-2.14.6-cp310-none-win32.whl", hash = "sha256:7be719e4d2ae6c314f72844ba9d69e38dff342bc360379f7c8537c48e23034b7"}, - {file = "pydantic_core-2.14.6-cp310-none-win_amd64.whl", hash = "sha256:36fa402dcdc8ea7f1b0ddcf0df4254cc6b2e08f8cd80e7010d4c4ae6e86b2a87"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:dea7fcd62915fb150cdc373212141a30037e11b761fbced340e9db3379b892d4"}, - {file = "pydantic_core-2.14.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ffff855100bc066ff2cd3aa4a60bc9534661816b110f0243e59503ec2df38421"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1b027c86c66b8627eb90e57aee1f526df77dc6d8b354ec498be9a757d513b92b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:00b1087dabcee0b0ffd104f9f53d7d3eaddfaa314cdd6726143af6bc713aa27e"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:75ec284328b60a4e91010c1acade0c30584f28a1f345bc8f72fe8b9e46ec6a96"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e1f4744eea1501404b20b0ac059ff7e3f96a97d3e3f48ce27a139e053bb370b"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b2602177668f89b38b9f84b7b3435d0a72511ddef45dc14446811759b82235a1"}, - {file = "pydantic_core-2.14.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6c8edaea3089bf908dd27da8f5d9e395c5b4dc092dbcce9b65e7156099b4b937"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:478e9e7b360dfec451daafe286998d4a1eeaecf6d69c427b834ae771cad4b622"}, - {file = "pydantic_core-2.14.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b6ca36c12a5120bad343eef193cc0122928c5c7466121da7c20f41160ba00ba2"}, - {file = "pydantic_core-2.14.6-cp311-none-win32.whl", hash = "sha256:2b8719037e570639e6b665a4050add43134d80b687288ba3ade18b22bbb29dd2"}, - {file = "pydantic_core-2.14.6-cp311-none-win_amd64.whl", hash = "sha256:78ee52ecc088c61cce32b2d30a826f929e1708f7b9247dc3b921aec367dc1b23"}, - {file = "pydantic_core-2.14.6-cp311-none-win_arm64.whl", hash = "sha256:a19b794f8fe6569472ff77602437ec4430f9b2b9ec7a1105cfd2232f9ba355e6"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:667aa2eac9cd0700af1ddb38b7b1ef246d8cf94c85637cbb03d7757ca4c3fdec"}, - {file = "pydantic_core-2.14.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cdee837710ef6b56ebd20245b83799fce40b265b3b406e51e8ccc5b85b9099b7"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2c5bcf3414367e29f83fd66f7de64509a8fd2368b1edf4351e862910727d3e51"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:26a92ae76f75d1915806b77cf459811e772d8f71fd1e4339c99750f0e7f6324f"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a983cca5ed1dd9a35e9e42ebf9f278d344603bfcb174ff99a5815f953925140a"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cb92f9061657287eded380d7dc455bbf115430b3aa4741bdc662d02977e7d0af"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4ace1e220b078c8e48e82c081e35002038657e4b37d403ce940fa679e57113b"}, - {file = "pydantic_core-2.14.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef633add81832f4b56d3b4c9408b43d530dfca29e68fb1b797dcb861a2c734cd"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7e90d6cc4aad2cc1f5e16ed56e46cebf4877c62403a311af20459c15da76fd91"}, - {file = "pydantic_core-2.14.6-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e8a5ac97ea521d7bde7621d86c30e86b798cdecd985723c4ed737a2aa9e77d0c"}, - {file = "pydantic_core-2.14.6-cp312-none-win32.whl", hash = "sha256:f27207e8ca3e5e021e2402ba942e5b4c629718e665c81b8b306f3c8b1ddbb786"}, - {file = "pydantic_core-2.14.6-cp312-none-win_amd64.whl", hash = "sha256:b3e5fe4538001bb82e2295b8d2a39356a84694c97cb73a566dc36328b9f83b40"}, - {file = "pydantic_core-2.14.6-cp312-none-win_arm64.whl", hash = "sha256:64634ccf9d671c6be242a664a33c4acf12882670b09b3f163cd00a24cffbd74e"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:24368e31be2c88bd69340fbfe741b405302993242ccb476c5c3ff48aeee1afe0"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:e33b0834f1cf779aa839975f9d8755a7c2420510c0fa1e9fa0497de77cd35d2c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6af4b3f52cc65f8a0bc8b1cd9676f8c21ef3e9132f21fed250f6958bd7223bed"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d15687d7d7f40333bd8266f3814c591c2e2cd263fa2116e314f60d82086e353a"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:095b707bb287bfd534044166ab767bec70a9bba3175dcdc3371782175c14e43c"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94fc0e6621e07d1e91c44e016cc0b189b48db053061cc22d6298a611de8071bb"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce830e480f6774608dedfd4a90c42aac4a7af0a711f1b52f807130c2e434c06"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a306cdd2ad3a7d795d8e617a58c3a2ed0f76c8496fb7621b6cd514eb1532cae8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:2f5fa187bde8524b1e37ba894db13aadd64faa884657473b03a019f625cee9a8"}, - {file = "pydantic_core-2.14.6-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:438027a975cc213a47c5d70672e0d29776082155cfae540c4e225716586be75e"}, - {file = "pydantic_core-2.14.6-cp37-none-win32.whl", hash = "sha256:f96ae96a060a8072ceff4cfde89d261837b4294a4f28b84a28765470d502ccc6"}, - {file = "pydantic_core-2.14.6-cp37-none-win_amd64.whl", hash = "sha256:e646c0e282e960345314f42f2cea5e0b5f56938c093541ea6dbf11aec2862391"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:db453f2da3f59a348f514cfbfeb042393b68720787bbef2b4c6068ea362c8149"}, - {file = "pydantic_core-2.14.6-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3860c62057acd95cc84044e758e47b18dcd8871a328ebc8ccdefd18b0d26a21b"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36026d8f99c58d7044413e1b819a67ca0e0b8ebe0f25e775e6c3d1fabb3c38fb"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ed1af8692bd8d2a29d702f1a2e6065416d76897d726e45a1775b1444f5928a7"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:314ccc4264ce7d854941231cf71b592e30d8d368a71e50197c905874feacc8a8"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:982487f8931067a32e72d40ab6b47b1628a9c5d344be7f1a4e668fb462d2da42"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dbe357bc4ddda078f79d2a36fc1dd0494a7f2fad83a0a684465b6f24b46fe80"}, - {file = "pydantic_core-2.14.6-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2f6ffc6701a0eb28648c845f4945a194dc7ab3c651f535b81793251e1185ac3d"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7f5025db12fc6de7bc1104d826d5aee1d172f9ba6ca936bf6474c2148ac336c1"}, - {file = "pydantic_core-2.14.6-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:dab03ed811ed1c71d700ed08bde8431cf429bbe59e423394f0f4055f1ca0ea60"}, - {file = "pydantic_core-2.14.6-cp38-none-win32.whl", hash = "sha256:dfcbebdb3c4b6f739a91769aea5ed615023f3c88cb70df812849aef634c25fbe"}, - {file = "pydantic_core-2.14.6-cp38-none-win_amd64.whl", hash = "sha256:99b14dbea2fdb563d8b5a57c9badfcd72083f6006caf8e126b491519c7d64ca8"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:4ce8299b481bcb68e5c82002b96e411796b844d72b3e92a3fbedfe8e19813eab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b9a9d92f10772d2a181b5ca339dee066ab7d1c9a34ae2421b2a52556e719756f"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fd9e98b408384989ea4ab60206b8e100d8687da18b5c813c11e92fd8212a98e0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4f86f1f318e56f5cbb282fe61eb84767aee743ebe32c7c0834690ebea50c0a6b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86ce5fcfc3accf3a07a729779d0b86c5d0309a4764c897d86c11089be61da160"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dcf1978be02153c6a31692d4fbcc2a3f1db9da36039ead23173bc256ee3b91b"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eedf97be7bc3dbc8addcef4142f4b4164066df0c6f36397ae4aaed3eb187d8ab"}, - {file = "pydantic_core-2.14.6-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5f916acf8afbcab6bacbb376ba7dc61f845367901ecd5e328fc4d4aef2fcab0"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:8a14c192c1d724c3acbfb3f10a958c55a2638391319ce8078cb36c02283959b9"}, - {file = "pydantic_core-2.14.6-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0348b1dc6b76041516e8a854ff95b21c55f5a411c3297d2ca52f5528e49d8411"}, - {file = "pydantic_core-2.14.6-cp39-none-win32.whl", hash = "sha256:de2a0645a923ba57c5527497daf8ec5df69c6eadf869e9cd46e86349146e5975"}, - {file = "pydantic_core-2.14.6-cp39-none-win_amd64.whl", hash = "sha256:aca48506a9c20f68ee61c87f2008f81f8ee99f8d7f0104bff3c47e2d148f89d9"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:d5c28525c19f5bb1e09511669bb57353d22b94cf8b65f3a8d141c389a55dec95"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:78d0768ee59baa3de0f4adac9e3748b4b1fffc52143caebddfd5ea2961595277"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b93785eadaef932e4fe9c6e12ba67beb1b3f1e5495631419c784ab87e975670"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a874f21f87c485310944b2b2734cd6d318765bcbb7515eead33af9641816506e"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b89f4477d915ea43b4ceea6756f63f0288941b6443a2b28c69004fe07fde0d0d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:172de779e2a153d36ee690dbc49c6db568d7b33b18dc56b69a7514aecbcf380d"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:dfcebb950aa7e667ec226a442722134539e77c575f6cfaa423f24371bb8d2e94"}, - {file = "pydantic_core-2.14.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:55a23dcd98c858c0db44fc5c04fc7ed81c4b4d33c653a7c45ddaebf6563a2f66"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4241204e4b36ab5ae466ecec5c4c16527a054c69f99bba20f6f75232a6a534e2"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e574de99d735b3fc8364cba9912c2bec2da78775eba95cbb225ef7dda6acea24"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1302a54f87b5cd8528e4d6d1bf2133b6aa7c6122ff8e9dc5220fbc1e07bffebd"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f8e81e4b55930e5ffab4a68db1af431629cf2e4066dbdbfef65348b8ab804ea8"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:c99462ffc538717b3e60151dfaf91125f637e801f5ab008f81c402f1dff0cd0f"}, - {file = "pydantic_core-2.14.6-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e4cf2d5829f6963a5483ec01578ee76d329eb5caf330ecd05b3edd697e7d768a"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:cf10b7d58ae4a1f07fccbf4a0a956d705356fea05fb4c70608bb6fa81d103cda"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:399ac0891c284fa8eb998bcfa323f2234858f5d2efca3950ae58c8f88830f145"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c6a5c79b28003543db3ba67d1df336f253a87d3112dac3a51b94f7d48e4c0e1"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:599c87d79cab2a6a2a9df4aefe0455e61e7d2aeede2f8577c1b7c0aec643ee8e"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43e166ad47ba900f2542a80d83f9fc65fe99eb63ceec4debec160ae729824052"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3a0b5db001b98e1c649dd55afa928e75aa4087e587b9524a4992316fa23c9fba"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:747265448cb57a9f37572a488a57d873fd96bf51e5bb7edb52cfb37124516da4"}, - {file = "pydantic_core-2.14.6-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:7ebe3416785f65c28f4f9441e916bfc8a54179c8dea73c23023f7086fa601c5d"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:86c963186ca5e50d5c8287b1d1c9d3f8f024cbe343d048c5bd282aec2d8641f2"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:e0641b506486f0b4cd1500a2a65740243e8670a2549bb02bc4556a83af84ae03"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71d72ca5eaaa8d38c8df16b7deb1a2da4f650c41b58bb142f3fb75d5ad4a611f"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:27e524624eace5c59af499cd97dc18bb201dc6a7a2da24bfc66ef151c69a5f2a"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a3dde6cac75e0b0902778978d3b1646ca9f438654395a362cb21d9ad34b24acf"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:00646784f6cd993b1e1c0e7b0fdcbccc375d539db95555477771c27555e3c556"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:23598acb8ccaa3d1d875ef3b35cb6376535095e9405d91a3d57a8c7db5d29341"}, - {file = "pydantic_core-2.14.6-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7f41533d7e3cf9520065f610b41ac1c76bc2161415955fbcead4981b22c7611e"}, - {file = "pydantic_core-2.14.6.tar.gz", hash = "sha256:1fd0c1d395372843fba13a51c28e3bb9d59bd7aebfeb17358ffaaa1e4dbbe948"}, + {file = "pydantic_core-2.16.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:300616102fb71241ff477a2cbbc847321dbec49428434a2f17f37528721c4948"}, + {file = "pydantic_core-2.16.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5511f962dd1b9b553e9534c3b9c6a4b0c9ded3d8c2be96e61d56f933feef9e1f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98f0edee7ee9cc7f9221af2e1b95bd02810e1c7a6d115cfd82698803d385b28f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9795f56aa6b2296f05ac79d8a424e94056730c0b860a62b0fdcfe6340b658cc8"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c45f62e4107ebd05166717ac58f6feb44471ed450d07fecd90e5f69d9bf03c48"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462d599299c5971f03c676e2b63aa80fec5ebc572d89ce766cd11ca8bcb56f3f"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21ebaa4bf6386a3b22eec518da7d679c8363fb7fb70cf6972161e5542f470798"}, + {file = "pydantic_core-2.16.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:99f9a50b56713a598d33bc23a9912224fc5d7f9f292444e6664236ae471ddf17"}, + {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8ec364e280db4235389b5e1e6ee924723c693cbc98e9d28dc1767041ff9bc388"}, + {file = "pydantic_core-2.16.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:653a5dfd00f601a0ed6654a8b877b18d65ac32c9d9997456e0ab240807be6cf7"}, + {file = "pydantic_core-2.16.1-cp310-none-win32.whl", hash = "sha256:1661c668c1bb67b7cec96914329d9ab66755911d093bb9063c4c8914188af6d4"}, + {file = "pydantic_core-2.16.1-cp310-none-win_amd64.whl", hash = "sha256:561be4e3e952c2f9056fba5267b99be4ec2afadc27261505d4992c50b33c513c"}, + {file = "pydantic_core-2.16.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:102569d371fadc40d8f8598a59379c37ec60164315884467052830b28cc4e9da"}, + {file = "pydantic_core-2.16.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:735dceec50fa907a3c314b84ed609dec54b76a814aa14eb90da31d1d36873a5e"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e83ebbf020be727d6e0991c1b192a5c2e7113eb66e3def0cd0c62f9f266247e4"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:30a8259569fbeec49cfac7fda3ec8123486ef1b729225222f0d41d5f840b476f"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:920c4897e55e2881db6a6da151198e5001552c3777cd42b8a4c2f72eedc2ee91"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5247a3d74355f8b1d780d0f3b32a23dd9f6d3ff43ef2037c6dcd249f35ecf4c"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d5bea8012df5bb6dda1e67d0563ac50b7f64a5d5858348b5c8cb5043811c19d"}, + {file = "pydantic_core-2.16.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ed3025a8a7e5a59817b7494686d449ebfbe301f3e757b852c8d0d1961d6be864"}, + {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:06f0d5a1d9e1b7932477c172cc720b3b23c18762ed7a8efa8398298a59d177c7"}, + {file = "pydantic_core-2.16.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:150ba5c86f502c040b822777e2e519b5625b47813bd05f9273a8ed169c97d9ae"}, + {file = "pydantic_core-2.16.1-cp311-none-win32.whl", hash = "sha256:d6cbdf12ef967a6aa401cf5cdf47850559e59eedad10e781471c960583f25aa1"}, + {file = "pydantic_core-2.16.1-cp311-none-win_amd64.whl", hash = "sha256:afa01d25769af33a8dac0d905d5c7bb2d73c7c3d5161b2dd6f8b5b5eea6a3c4c"}, + {file = "pydantic_core-2.16.1-cp311-none-win_arm64.whl", hash = "sha256:1a2fe7b00a49b51047334d84aafd7e39f80b7675cad0083678c58983662da89b"}, + {file = "pydantic_core-2.16.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:0f478ec204772a5c8218e30eb813ca43e34005dff2eafa03931b3d8caef87d51"}, + {file = "pydantic_core-2.16.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1936ef138bed2165dd8573aa65e3095ef7c2b6247faccd0e15186aabdda7f66"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:99d3a433ef5dc3021c9534a58a3686c88363c591974c16c54a01af7efd741f13"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd88f40f2294440d3f3c6308e50d96a0d3d0973d6f1a5732875d10f569acef49"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fac641bbfa43d5a1bed99d28aa1fded1984d31c670a95aac1bf1d36ac6ce137"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:72bf9308a82b75039b8c8edd2be2924c352eda5da14a920551a8b65d5ee89253"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb4363e6c9fc87365c2bc777a1f585a22f2f56642501885ffc7942138499bf54"}, + {file = "pydantic_core-2.16.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:20f724a023042588d0f4396bbbcf4cffd0ddd0ad3ed4f0d8e6d4ac4264bae81e"}, + {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:fb4370b15111905bf8b5ba2129b926af9470f014cb0493a67d23e9d7a48348e8"}, + {file = "pydantic_core-2.16.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23632132f1fd608034f1a56cc3e484be00854db845b3a4a508834be5a6435a6f"}, + {file = "pydantic_core-2.16.1-cp312-none-win32.whl", hash = "sha256:b9f3e0bffad6e238f7acc20c393c1ed8fab4371e3b3bc311020dfa6020d99212"}, + {file = "pydantic_core-2.16.1-cp312-none-win_amd64.whl", hash = "sha256:a0b4cfe408cd84c53bab7d83e4209458de676a6ec5e9c623ae914ce1cb79b96f"}, + {file = "pydantic_core-2.16.1-cp312-none-win_arm64.whl", hash = "sha256:d195add190abccefc70ad0f9a0141ad7da53e16183048380e688b466702195dd"}, + {file = "pydantic_core-2.16.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:502c062a18d84452858f8aea1e520e12a4d5228fc3621ea5061409d666ea1706"}, + {file = "pydantic_core-2.16.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d8c032ccee90b37b44e05948b449a2d6baed7e614df3d3f47fe432c952c21b60"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:920f4633bee43d7a2818e1a1a788906df5a17b7ab6fe411220ed92b42940f818"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9f5d37ff01edcbace53a402e80793640c25798fb7208f105d87a25e6fcc9ea06"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:399166f24c33a0c5759ecc4801f040dbc87d412c1a6d6292b2349b4c505effc9"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ac89ccc39cd1d556cc72d6752f252dc869dde41c7c936e86beac5eb555041b66"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:73802194f10c394c2bedce7a135ba1d8ba6cff23adf4217612bfc5cf060de34c"}, + {file = "pydantic_core-2.16.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8fa00fa24ffd8c31fac081bf7be7eb495be6d248db127f8776575a746fa55c95"}, + {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:601d3e42452cd4f2891c13fa8c70366d71851c1593ed42f57bf37f40f7dca3c8"}, + {file = "pydantic_core-2.16.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07982b82d121ed3fc1c51faf6e8f57ff09b1325d2efccaa257dd8c0dd937acca"}, + {file = "pydantic_core-2.16.1-cp38-none-win32.whl", hash = "sha256:d0bf6f93a55d3fa7a079d811b29100b019784e2ee6bc06b0bb839538272a5610"}, + {file = "pydantic_core-2.16.1-cp38-none-win_amd64.whl", hash = "sha256:fbec2af0ebafa57eb82c18c304b37c86a8abddf7022955d1742b3d5471a6339e"}, + {file = "pydantic_core-2.16.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a497be217818c318d93f07e14502ef93d44e6a20c72b04c530611e45e54c2196"}, + {file = "pydantic_core-2.16.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:694a5e9f1f2c124a17ff2d0be613fd53ba0c26de588eb4bdab8bca855e550d95"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d4dfc66abea3ec6d9f83e837a8f8a7d9d3a76d25c9911735c76d6745950e62c"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8655f55fe68c4685673265a650ef71beb2d31871c049c8b80262026f23605ee3"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21e3298486c4ea4e4d5cc6fb69e06fb02a4e22089304308817035ac006a7f506"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:71b4a48a7427f14679f0015b13c712863d28bb1ab700bd11776a5368135c7d60"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10dca874e35bb60ce4f9f6665bfbfad050dd7573596608aeb9e098621ac331dc"}, + {file = "pydantic_core-2.16.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa496cd45cda0165d597e9d6f01e36c33c9508f75cf03c0a650018c5048f578e"}, + {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5317c04349472e683803da262c781c42c5628a9be73f4750ac7d13040efb5d2d"}, + {file = "pydantic_core-2.16.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:42c29d54ed4501a30cd71015bf982fa95e4a60117b44e1a200290ce687d3e640"}, + {file = "pydantic_core-2.16.1-cp39-none-win32.whl", hash = "sha256:ba07646f35e4e49376c9831130039d1b478fbfa1215ae62ad62d2ee63cf9c18f"}, + {file = "pydantic_core-2.16.1-cp39-none-win_amd64.whl", hash = "sha256:2133b0e412a47868a358713287ff9f9a328879da547dc88be67481cdac529118"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d25ef0c33f22649b7a088035fd65ac1ce6464fa2876578df1adad9472f918a76"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:99c095457eea8550c9fa9a7a992e842aeae1429dab6b6b378710f62bfb70b394"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b49c604ace7a7aa8af31196abbf8f2193be605db6739ed905ecaf62af31ccae0"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c56da23034fe66221f2208c813d8aa509eea34d97328ce2add56e219c3a9f41c"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cebf8d56fee3b08ad40d332a807ecccd4153d3f1ba8231e111d9759f02edfd05"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:1ae8048cba95f382dba56766525abca438328455e35c283bb202964f41a780b0"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:780daad9e35b18d10d7219d24bfb30148ca2afc309928e1d4d53de86822593dc"}, + {file = "pydantic_core-2.16.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:c94b5537bf6ce66e4d7830c6993152940a188600f6ae044435287753044a8fe2"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:adf28099d061a25fbcc6531febb7a091e027605385de9fe14dd6a97319d614cf"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:644904600c15816a1f9a1bafa6aab0d21db2788abcdf4e2a77951280473f33e1"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87bce04f09f0552b66fca0c4e10da78d17cb0e71c205864bab4e9595122cb9d9"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:877045a7969ace04d59516d5d6a7dee13106822f99a5d8df5e6822941f7bedc8"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9c46e556ee266ed3fb7b7a882b53df3c76b45e872fdab8d9cf49ae5e91147fd7"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4eebbd049008eb800f519578e944b8dc8e0f7d59a5abb5924cc2d4ed3a1834ff"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:c0be58529d43d38ae849a91932391eb93275a06b93b79a8ab828b012e916a206"}, + {file = "pydantic_core-2.16.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b1fc07896fc1851558f532dffc8987e526b682ec73140886c831d773cef44b76"}, + {file = "pydantic_core-2.16.1.tar.gz", hash = "sha256:daff04257b49ab7f4b3f73f98283d3dbb1a65bf3500d55c7beac3c66c310fe34"}, ] [package.dependencies] @@ -1965,13 +1939,13 @@ cli = ["click (>=5.0)"] [[package]] name = "pytz" -version = "2023.3.post1" +version = "2023.4" description = "World timezone definitions, modern and historical" optional = false python-versions = "*" files = [ - {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, - {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, + {file = "pytz-2023.4-py2.py3-none-any.whl", hash = "sha256:f90ef520d95e7c46951105338d918664ebfd6f1d995bd7d153127ce90efafa6a"}, + {file = "pytz-2023.4.tar.gz", hash = "sha256:31d4583c4ed539cd037956140d695e42c033a19e984bfce9964a3f7d59bc2b40"}, ] [[package]] diff --git a/src/valentina/cogs/gameplay.py b/src/valentina/cogs/gameplay.py index b79c881f..2c9f1619 100644 --- a/src/valentina/cogs/gameplay.py +++ b/src/valentina/cogs/gameplay.py @@ -11,7 +11,12 @@ from valentina.models import User from valentina.models.bot import Valentina, ValentinaContext from valentina.utils import random_num -from valentina.utils.autocomplete import select_char_trait, select_char_trait_two, select_macro +from valentina.utils.autocomplete import ( + select_char_trait, + select_char_trait_two, + select_desperation_dice, + select_macro, +) from valentina.utils.converters import ValidTraitFromID from valentina.utils.perform_roll import perform_roll from valentina.views import present_embed @@ -37,6 +42,13 @@ async def throw( required=False, default=DEFAULT_DIFFICULTY, ), + desperation: Option( + int, + description="Add desperation dice", + required=False, + default=0, + autocomplete=select_desperation_dice, + ), comment: Option(str, "A comment to display with the roll", required=False, default=None), ) -> None: """Roll the dice. @@ -45,12 +57,33 @@ async def throw( comment (str, optional): A comment to display with the roll. Defaults to None. ctx (ValentinaContext): The context of the command difficulty (int): The difficulty of the roll + desperation (int): Add x desperation dice to the roll pool (int): The number of dice to roll """ # Grab the player's active character for statistic logging purposes character = await ctx.fetch_active_character(raise_error=False) - await perform_roll(ctx, pool, difficulty, DiceType.D10.value, comment, character=character) + if desperation > 0: + active_campaign = await ctx.fetch_active_campaign() + if active_campaign.desperation == 0 or desperation > 5: # noqa: PLR2004 + await present_embed( + ctx, + title="Can not roll desperation", + description="The current desperation level is 0. No dice to roll.", + level="error", + ephemeral=True, + ) + return + + await perform_roll( + ctx, + pool, + difficulty, + DiceType.D10.value, + comment, + character=character, + desperation_pool=desperation, + ) @roll.command(name="traits", description="Throw a roll based on trait names") async def traits( @@ -76,6 +109,13 @@ async def traits( required=False, default=DEFAULT_DIFFICULTY, ), + desperation: Option( + int, + description="Add desperation dice", + required=False, + default=0, + autocomplete=select_desperation_dice, + ), comment: Option(str, "A comment to display with the roll", required=False, default=None), ) -> None: """Roll the total number of d10s for two given traits against a difficulty.""" @@ -88,6 +128,18 @@ async def traits( LogLevel.DEBUG, ) + if desperation > 0: + active_campaign = await ctx.fetch_active_campaign() + if active_campaign.desperation == 0 or desperation > 5: # noqa: PLR2004 + await present_embed( + ctx, + title="Can not roll desperation", + description="The current desperation level is 0. No dice to roll.", + level="error", + ephemeral=True, + ) + return + await perform_roll( ctx, pool, @@ -97,6 +149,7 @@ async def traits( trait_one=trait_one, trait_two=trait_two, character=character, + desperation_pool=desperation, ) @roll.command(description="Simple dice roll of any size.") @@ -134,6 +187,13 @@ async def roll_macro( required=False, default=DEFAULT_DIFFICULTY, ), + desperation: Option( + int, + description="Add desperation dice", + required=False, + default=0, + autocomplete=select_desperation_dice, + ), comment: Option(str, "A comment to display with the roll", required=False, default=None), ) -> None: """Roll a macro.""" @@ -148,6 +208,18 @@ async def roll_macro( msg = "Macro traits not found on character" raise commands.BadArgument(msg) + if desperation > 0: + active_campaign = await ctx.fetch_active_campaign() + if active_campaign.desperation == 0 or desperation > 5: # noqa: PLR2004 + await present_embed( + ctx, + title="Can not roll desperation", + description="The current desperation level is 0. No dice to roll.", + level="error", + ephemeral=True, + ) + return + ctx.log_command( f"Macro: {macro.name}: {trait_one.name} ({trait_one.id}) + {trait_two.name} ({trait_two.id})", LogLevel.DEBUG, @@ -164,6 +236,50 @@ async def roll_macro( trait_one=trait_one, trait_two=trait_two, character=character, + desperation_pool=desperation, + ) + + @roll.command(name="desperation", description="Roll desperation") + async def roll_desperation( + self, + ctx: ValentinaContext, + desperation: Option( + int, + description="Add desperation dice", + required=True, + autocomplete=select_desperation_dice, + ), + difficulty: Option( + int, + "The difficulty of the roll", + required=False, + default=DEFAULT_DIFFICULTY, + ), + comment: Option(str, "A comment to display with the roll", required=False, default=None), + ) -> None: + """Roll desperation dice.""" + active_campaign = await ctx.fetch_active_campaign() + if active_campaign.desperation == 0 or desperation > 5: # noqa: PLR2004 + await present_embed( + ctx, + title="Can not roll desperation", + description="The current desperation level is 0. No dice to roll.", + level="error", + ephemeral=True, + ) + return + + # Grab the player's active character for statistic logging purposes + character = await ctx.fetch_active_character(raise_error=False) + + await perform_roll( + ctx, + 0, + difficulty, + DiceType.D10.value, + comment, + character=character, + desperation_pool=desperation, ) ### GAMEPLAY COMMANDS ### diff --git a/src/valentina/constants.py b/src/valentina/constants.py index ac80ebbf..a78b95cd 100644 --- a/src/valentina/constants.py +++ b/src/valentina/constants.py @@ -16,16 +16,7 @@ ### Single constants ### -COOL_POINT_VALUE = 10 # 1 cool point equals this many xp -DEFAULT_DIFFICULTY = 6 # Default difficulty for a roll -MAX_BUTTONS_PER_ROW = 5 -MAX_DOT_DISPLAY = 5 # number of dots to display on a character sheet before converting to text -MAX_FIELD_COUNT = 1010 -MAX_OPTION_LIST_SIZE = 25 # maximum number of options in a discord select menu -PREF_MAX_EMBED_CHARACTERS = 1950 # Preferred maximum number of characters in an embed ABS_MAX_EMBED_CHARACTERS = 3900 # Absolute maximum number of characters in an embed -100 for safety -VALID_IMAGE_EXTENSIONS = frozenset(["png", "jpg", "jpeg", "gif", "webp"]) -CHANGELOG_PATH = Path(__file__).parent / "../../CHANGELOG.md" CHANGELOG_EXCLUDE_CATEGORIES = [ "docs", "refactor", @@ -36,6 +27,17 @@ "ci", "build", ] +CHANGELOG_PATH = Path(__file__).parent / "../../CHANGELOG.md" +COOL_POINT_VALUE = 10 # 1 cool point equals this many xp +DEFAULT_DIFFICULTY = 6 # Default difficulty for a roll +MAX_BUTTONS_PER_ROW = 5 +MAX_DOT_DISPLAY = 5 # number of dots to display on a character sheet before converting to text +MAX_FIELD_COUNT = 1010 +MAX_OPTION_LIST_SIZE = 25 # maximum number of options in a discord select menu +MAX_POOL_SIZE = 100 # maximum number of dice that can be rolled +PREF_MAX_EMBED_CHARACTERS = 1950 # Preferred maximum number of characters in an embed +SPACER = "\u200b" # Zero-width space +VALID_IMAGE_EXTENSIONS = frozenset(["png", "jpg", "jpeg", "gif", "webp"]) ### ENUMS ### @@ -92,6 +94,8 @@ class Emoji(Enum): CANCEL = "🚫" COOL_POINT = "🆒" DEAD = "💀" + DESPAIR = "😰" + DICE = "🎲" ERROR = "❌" GHOST = "👻" HUNTER = "🧑🏹" @@ -99,18 +103,19 @@ class Emoji(Enum): MONSTER = "👹" MORTAL = "🧑" NO = "❌" - PENCIL = "✏️" OTHER = "🤷" + OVERREACH = "😱" + PENCIL = "✏️" QUESTION = "❓" + RECYCLE = "♻️" + RELOAD = "🔄" + SETTING = "⚙️" SUCCESS = "👍" VAMPIRE = "🧛" WARNING = "⚠️" WEREWOLF = "🐺" YES = "✅" - SETTING = "⚙️" - RECYCLE = "♻️" - RELOAD = "🔄" - DICE = "🎲" + FACEPALM = "🤦" class GithubIssueLabels(Enum): diff --git a/src/valentina/models/dicerolls.py b/src/valentina/models/dicerolls.py index 7ed7edf3..de24a674 100644 --- a/src/valentina/models/dicerolls.py +++ b/src/valentina/models/dicerolls.py @@ -4,14 +4,12 @@ import inflect from loguru import logger -from valentina.constants import DiceType, EmbedColor, RollResultType +from valentina.constants import MAX_POOL_SIZE, DiceType, EmbedColor, RollResultType from valentina.models import Character, Guild, RollStatistic from valentina.utils import errors, random_num p = inflect.engine() -_max_pool_size = 100 - class DiceRoll: """A container class that determines the result of a roll and logs dicerolls to the database. @@ -33,6 +31,8 @@ class DiceRoll: Attributes: botches (int): The number of ones in the dice. criticals (int): The number of rolled criticals (Highest number on dice). + desperation_roll (list[int]): A list of the result all rolled desperation dice. + desperation_botches (int): The number of ones in the desperation dice. dice_type (DiceType): The type of dice to roll. difficulty (int): The difficulty of the roll. embed_color (int): The color of the embed. @@ -57,6 +57,7 @@ def __init__( difficulty: int = 6, dice_size: int = 10, character: Character = None, + desperation_pool: int = 0, ) -> None: """A container class that determines the result of a roll. @@ -66,9 +67,11 @@ def __init__( difficulty (int, optional): The difficulty of the roll. Defaults to 6. pool (int): The pool's total size, including hunger character (Character, optional): The character to log the roll for. Defaults to None. + desperation_pool (int): The number of dice to roll from the desperation pool. Defaults to 0. """ self.ctx = ctx self.character = character + self.desperation_pool = desperation_pool dice_size_values = [member.value for member in DiceType] if dice_size not in dice_size_values: @@ -86,21 +89,24 @@ def __init__( if pool < 0: msg = f"Pool cannot be less than 0. (Got `{pool}`.)" raise errors.ValidationError(msg) - if pool > _max_pool_size: - msg = f"Pool cannot exceed {_max_pool_size}. (Got `{pool}`.)" + if pool > MAX_POOL_SIZE: + msg = f"Pool cannot exceed {MAX_POOL_SIZE}. (Got `{pool}`.)" raise errors.ValidationError(msg) self.difficulty = difficulty self.pool = pool self._roll: list[int] = None + self._desperation_roll: list[int] = None self._botches: int = None self._criticals: int = None self._failures: int = None self._successes: int = None self._result: int = None self._result_type: RollResultType = None + self._desperation_botches: int = None def _calculate_result(self) -> RollResultType: + """Calculate the result type of the roll.""" if self.dice_type != DiceType.D10: return RollResultType.OTHER @@ -120,7 +126,6 @@ async def log_roll(self, traits: list[str] = []) -> None: Args: traits (list[str], optional): The traits to log the roll for. Defaults to []. - """ # Ensure the user in the database to avoid foreign key errors @@ -157,19 +162,46 @@ def roll(self) -> list[int]: return self._roll + @property + def desperation_roll(self) -> list[int]: + """Roll the desperation dice and return the results.""" + if not self._desperation_roll: + self._desperation_roll = [ + random_num(self.dice_type.value) for x in range(self.desperation_pool) + ] + + return self._desperation_roll + @property def botches(self) -> int: """Retrieve the number of ones in the dice.""" if not self._botches: - self._botches = self.roll.count(1) + if self.desperation_pool > 0: + desperation_botches = self.desperation_roll.count(1) + self._botches = self.roll.count(1) + desperation_botches + else: + self._botches = self.roll.count(1) return self._botches + @property + def desperation_botches(self) -> int: + """Retrieve the number of ones in the desperation dice.""" + if not self._desperation_botches and self.desperation_pool > 0: + self._desperation_botches = self.desperation_roll.count(1) + + return self._desperation_botches + @property def criticals(self) -> int: """Retrieve the number of rolled criticals (Highest number on dice).""" if not self._criticals: - self._criticals = self.roll.count(self.dice_type.value) + if self.desperation_pool > 0: + desperation_criticals = self.desperation_roll.count(self.dice_type.value) + self._criticals = self.roll.count(self.dice_type.value) + desperation_criticals + else: + self._criticals = self.roll.count(self.dice_type.value) + return self._criticals @property @@ -181,6 +213,14 @@ def failures(self) -> int: if 2 <= die <= self.difficulty - 1: # noqa: PLR2004 count += 1 self._failures = count + + if self.desperation_pool > 0: + desperation_failures = 0 + for die in self.desperation_roll: + if 2 <= die <= self.difficulty - 1: # noqa: PLR2004 + desperation_failures += 1 + self._failures += desperation_failures + return self._failures @property @@ -192,6 +232,14 @@ def successes(self) -> int: if self.difficulty <= die <= self.dice_type.value - 1: count += 1 self._successes = count + + if self.desperation_pool > 0: + desperation_successes = 0 + for die in self.desperation_roll: + if self.difficulty <= die <= self.dice_type.value - 1: + desperation_successes += 1 + self._successes += desperation_successes + return self._successes @property @@ -242,11 +290,11 @@ def embed_title(self) -> str: # pragma: no cover @property def embed_description(self) -> str: """The description of the roll response embed.""" - title_map = { + description_map = { RollResultType.OTHER: "", RollResultType.BOTCH: f"{self.result} {p.plural_noun('Success', self.result)}", RollResultType.CRITICAL: f"{self.result} {p.plural_noun('Success', self.result)}", RollResultType.SUCCESS: "", RollResultType.FAILURE: "", } - return title_map[self.result_type] + return description_map[self.result_type] diff --git a/src/valentina/utils/autocomplete.py b/src/valentina/utils/autocomplete.py index 78ae3e55..fcfc2832 100644 --- a/src/valentina/utils/autocomplete.py +++ b/src/valentina/utils/autocomplete.py @@ -3,6 +3,7 @@ from typing import cast import discord +import inflect from beanie.operators import And from discord.commands import OptionChoice @@ -22,6 +23,17 @@ MAX_OPTION_LENGTH = 99 +async def select_aws_object_from_guild(ctx: discord.AutocompleteContext) -> list[OptionChoice]: + """Populate the autocomplete list for the aws_object option based on the user's input.""" + aws_svc = AWSService() + + guild_prefix = f"{ctx.interaction.guild.id}/" + + return [OptionChoice(x.strip(guild_prefix), x) for x in aws_svc.list_objects(guild_prefix)][ + :MAX_OPTION_LIST_SIZE + ] + + async def select_changelog_version_1(ctx: discord.AutocompleteContext) -> list[str]: """Populate the autocomplete for the version option. This is for the first of two options.""" bot = cast(Valentina, ctx.bot) @@ -275,14 +287,33 @@ async def select_country(ctx: discord.AutocompleteContext) -> list[OptionChoice] ] -async def select_aws_object_from_guild(ctx: discord.AutocompleteContext) -> list[OptionChoice]: - """Populate the autocomplete list for the aws_object option based on the user's input.""" - aws_svc = AWSService() +async def select_desperation_dice(ctx: discord.AutocompleteContext) -> list[OptionChoice]: + """Populate the autocomplete list for the desperation_dice option based on the user's input. - guild_prefix = f"{ctx.interaction.guild.id}/" + This function creates a list of OptionChoice objects to populate the autocomplete list. - return [OptionChoice(x.strip(guild_prefix), x) for x in aws_svc.list_objects(guild_prefix)][ - :MAX_OPTION_LIST_SIZE + Args: + ctx (discord.AutocompleteContext): The context object containing interaction and user details. + + Returns: + list[OptionChoice]: A list of OptionChoice objects to populate the autocomplete list. + """ + p = inflect.engine() + + # Fetch the active campaign + guild = await Guild.get(ctx.interaction.guild.id, fetch_links=True) + active_campaign = await guild.fetch_active_campaign() + desperation_dice = active_campaign.desperation + + if not active_campaign: + return [OptionChoice("No active campaign", 1000)] + + if desperation_dice == 0: + return [OptionChoice("No desperation dice", 1000)] + + return [ + OptionChoice(f"{p.number_to_words(i).capitalize()} {p.plural('die', i)}", i) # type: ignore [arg-type, union-attr] + for i in range(1, desperation_dice + 1) ] diff --git a/src/valentina/utils/perform_roll.py b/src/valentina/utils/perform_roll.py index fc818cfe..82504c79 100644 --- a/src/valentina/utils/perform_roll.py +++ b/src/valentina/utils/perform_roll.py @@ -1,5 +1,8 @@ """Perform a diceroll.""" +import discord + +from valentina.constants import EmbedColor, Emoji from valentina.models import Character, CharacterTrait, DiceRoll from valentina.models.bot import ValentinaContext from valentina.views import ReRollButton, RollDisplay @@ -15,6 +18,7 @@ async def perform_roll( trait_one: CharacterTrait | None = None, trait_two: CharacterTrait | None = None, character: Character | None = None, + desperation_pool: int = 0, ) -> None: """Perform a dice roll and display the result. @@ -29,8 +33,16 @@ async def perform_roll( trait_one (CustomTrait, Trait, optional): The name of the first trait. Defaults to None. trait_two (CustomTrait, Trait, optional): The name of the second trait. Defaults to None. character (Character, optional): The ID of the character to log the roll for. Defaults to None. + desperation_pool (int, optional): The number of dice in the desperation pool. Defaults to 0. """ - roll = DiceRoll(ctx, pool=pool, difficulty=difficulty, dice_size=dice_size, character=character) + roll = DiceRoll( + ctx, + pool=pool, + difficulty=difficulty, + dice_size=dice_size, + character=character, + desperation_pool=desperation_pool, + ) traits_to_log = [] if trait_one: @@ -41,21 +53,56 @@ async def perform_roll( await roll.log_roll(traits=traits_to_log) while True: - view = ReRollButton(ctx.author) + view = ReRollButton( + author=ctx.author, + desperation_pool=desperation_pool, + desperation_botch=roll.desperation_botches > 0 if roll.desperation_botches else False, + ) embed = await RollDisplay( ctx, roll, comment, trait_one, trait_two, + desperation_pool=desperation_pool, ).get_embed() - await ctx.respond(embed=embed, view=view, ephemeral=hidden) + original_response = await ctx.respond(embed=embed, view=view, ephemeral=hidden) # Wait for a re-roll await view.wait() + if view.overreach: + active_campaign = await ctx.fetch_active_campaign() + if active_campaign.danger < 5: # noqa: PLR2004 + active_campaign.danger = active_campaign.danger + 1 + await active_campaign.save() + + await original_response.edit_original_response( # type: ignore [union-attr] + view=None, + embed=discord.Embed( + title=None, + description=f"# {Emoji.OVERREACH.value} Overreach!\nThe character overreached. This roll has succeeded but the danger level has increased to `{active_campaign.danger}`.", + color=EmbedColor.WARNING.value, + ), + ) + + if view.despair: + await original_response.edit_original_response( # type: ignore [union-attr] + view=None, + embed=discord.Embed( + title=None, + description=f"# {Emoji.DESPAIR.value} Despair!\n### This roll has failed and the character has entered Despair!\nYou can no longer use desperation dice until you redeem yourself.", + color=EmbedColor.WARNING.value, + ), + ) + if view.confirmed: roll = DiceRoll( - ctx, pool=pool, difficulty=difficulty, dice_size=dice_size, character=character + ctx, + pool=pool, + difficulty=difficulty, + dice_size=dice_size, + character=character, + desperation_pool=desperation_pool, ) await roll.log_roll(traits=traits_to_log) else: diff --git a/src/valentina/views/buttons.py b/src/valentina/views/buttons.py index 4e784379..d986a5c7 100644 --- a/src/valentina/views/buttons.py +++ b/src/valentina/views/buttons.py @@ -80,37 +80,88 @@ async def interaction_check(self, interaction: discord.Interaction) -> bool: class ReRollButton(discord.ui.View): - """Add a re-roll button to a view.""" + """Add a re-roll button to a view. When desperation botch is True, choices to enter Overreach or Despair will replace the re-roll button.""" - def __init__(self, author: discord.User | discord.Member | None = None): - super().__init__() + def __init__( + self, + author: discord.User | discord.Member | None = None, + desperation_pool: int = 0, + desperation_botch: bool = False, + ): + super().__init__(timeout=300) self.author = author + self.desperation_pool = desperation_pool + self.desperation_botch = desperation_botch self.confirmed: bool = None + self.overreach: bool = False + self.despair: bool = False + + ###################################################### + if self.desperation_pool == 0: # Add reroll and done buttons if not a desperation roll + reroll_button: Button = Button( + label="Re-Roll", + custom_id="reroll", + style=discord.ButtonStyle.success, + ) + reroll_button.callback = self.button_callback # type: ignore [method-assign] + self.add_item(reroll_button) - def _disable_all(self) -> None: - """Disable all buttons in the view.""" + done_button: Button = Button( + label="Done", custom_id="done", style=discord.ButtonStyle.secondary + ) + done_button.callback = self.button_callback # type: ignore [method-assign] + self.add_item(done_button) + elif desperation_botch: + overreach_button: Button = Button( + label=f"{Emoji.OVERREACH.value} Succeed and increase danger!", + custom_id="overreach", + style=discord.ButtonStyle.success, + ) + overreach_button.callback = self.button_callback # type: ignore [method-assign] + self.add_item(overreach_button) + + despair_button: Button = Button( + label=f"{Emoji.DESPAIR.value} Fail and enter Despair!", + custom_id="despair", + style=discord.ButtonStyle.success, + ) + despair_button.callback = self.button_callback # type: ignore [method-assign] + self.add_item(despair_button) + + ################################################################## + + async def button_callback(self, interaction: discord.Interaction) -> None: + """Respond to the button press and update the view.""" + # Get the custom_id of the button that was pressed + response = interaction.data.get("custom_id", None) + + # Disable the interaction and grab the setting name for child in self.children: - if isinstance(child, Button | discord.ui.Select): - child.disabled = True + if isinstance(child, Button) and response == child.custom_id: + child.label = f"{Emoji.YES.value} {child.label}" - @discord.ui.button(label="Re-Roll", style=discord.ButtonStyle.success, custom_id="reroll") - async def reroll_callback(self, button: Button, interaction: discord.Interaction) -> None: - """Callback for the re-roll button.""" - button.label += " ✅" self._disable_all() await interaction.response.edit_message(view=None) # view=None remove all buttons - self.confirmed = True - self.stop() - @discord.ui.button(label="Done", style=discord.ButtonStyle.secondary, custom_id="done") - async def done_callback(self, button: Button, interaction: discord.Interaction) -> None: - """Callback for the re-roll button.""" - button.label += f" {Emoji.YES.value}" - self._disable_all() - await interaction.response.edit_message(view=None) # view=None remove all buttons - self.confirmed = False + if response == "done": + self.confirmed = False + if response == "reroll": + self.confirmed = True + if response == "overreach": + self.confirmed = False + self.overreach = True + if response == "despair": + self.confirmed = False + self.despair = True + self.stop() + def _disable_all(self) -> None: + """Disable all buttons in the view.""" + for child in self.children: + if isinstance(child, Button | discord.ui.Select): + child.disabled = True + async def interaction_check(self, interaction: discord.Interaction) -> bool: """Disables buttons for everyone except the user who created the embed.""" if self.author is None: diff --git a/src/valentina/views/roll_display.py b/src/valentina/views/roll_display.py index 780c16da..88e95304 100644 --- a/src/valentina/views/roll_display.py +++ b/src/valentina/views/roll_display.py @@ -3,6 +3,7 @@ import discord import inflect +from valentina.constants import Emoji from valentina.models import CharacterTrait, DiceRoll from valentina.models.bot import ValentinaContext @@ -22,12 +23,14 @@ def __init__( comment: str | None = None, trait_one: CharacterTrait | None = None, trait_two: CharacterTrait | None = None, + desperation_pool: int = 0, ): self.ctx = ctx self.roll = roll self.comment = comment self.trait_one = trait_one self.trait_two = trait_two + self.desperation_pool = desperation_pool def _add_comment_field(self, embed: discord.Embed) -> discord.Embed: """Add the comment field to the embed.""" @@ -36,56 +39,63 @@ def _add_comment_field(self, embed: discord.Embed) -> discord.Embed: return embed - def _add_roll_fields(self, embed: discord.Embed) -> discord.Embed: - """Add the roll fields to the embed.""" - roll_string = " ".join(f"`{die}`" for die in self.roll.roll) - - embed.add_field( - name="\u200b", - value=f"{self.ctx.author.display_name} rolled **{self.roll.pool}{self.roll.dice_type.name.lower()}**", - inline=False, - ) - embed.add_field( - name=f"Dice: {roll_string}", - value="\u200b", - inline=False, - ) - if self.roll.dice_type.name == "D10": - embed.add_field(name="Pool", value=str(self.roll.pool), inline=True) - embed.add_field(name="Difficulty", value=str(self.roll.difficulty), inline=True) - - return embed - - def _add_trait_fields(self, embed: discord.Embed) -> discord.Embed: - """Add the trait fields to the embed.""" - if self.trait_one and self.trait_two: - embed.add_field( - name="**Rolled Traits**", - value=f"{self.trait_one.name}: `{self.trait_one.value} {p.plural_noun('die', self.trait_one.value)}`\n{self.trait_two.name}: `{self.trait_two.value} {p.plural_noun('die', self.trait_two.value)}`", - inline=False, - ) - elif self.trait_one: - embed.add_field( - name="**Rolled Traits**", - value=f"{self.trait_one.name}: `{self.trait_one.value} {p.plural_noun('die', self.trait_one.value)}`", - inline=False, - ) - - return embed - async def get_embed(self) -> discord.Embed: """The graphical representation of the roll.""" + roll_string = " ".join(f"{die}" for die in self.roll.roll) + if self.desperation_pool > 0: + desperation_roll_string = " ".join(f"{die}" for die in self.roll.desperation_roll) + + description = f"""\ +### {self.ctx.author.display_name} rolled `{self.desperation_pool + self.roll.pool}{self.roll.dice_type.name.lower()}` +## {self.roll.embed_title} +{self.roll.embed_description} +""" + + description += f"""\ +### Rolled Dice: +```scala +Roll : {roll_string} +{"Desperation : " + desperation_roll_string if self.desperation_pool > 0 else ""} +``` +""" + + if self.desperation_pool > 0 and self.roll.desperation_botches > 0: + description += f"""\ +### {Emoji.FACEPALM.value} `{self.roll.desperation_botches}` Desperation {p.plural_noun('botch', self.roll.desperation_botches)} +> You must pick either: +> - {Emoji.DESPAIR.value} **Despair** (Fail your roll) +> - {Emoji.OVERREACH.value} **Overreach** (Succeed but raise the danger level by 1) +""" + + description += f"""\ +### Roll Details: +```scala +Difficulty : {self.roll.difficulty} +Pool : {self.roll.pool}{self.roll.dice_type.name.lower()} +""" + + if self.desperation_pool > 0: + description += f"""\ +Desperation Pool : {self.desperation_pool}{self.roll.dice_type.name.lower()} +Total Dice Rolled: {self.desperation_pool + self.roll.pool}{self.roll.dice_type.name.lower()} +""" + + if self.trait_one: + description += f"{self.trait_one.name:<17}: {self.trait_one.value} {p.plural_noun('die', self.trait_one.value)}\n" + if self.trait_two: + description += f"{self.trait_two.name:<17}: {self.trait_two.value} {p.plural_noun('die', self.trait_two.value)}\n" + + description += "```" + embed = discord.Embed( - title=self.roll.embed_title, - description=self.roll.embed_description, + title=None, + description=description, color=self.roll.embed_color, ) # Thumbnail embed.set_thumbnail(url=await self.roll.thumbnail_url()) - embed = self._add_roll_fields(embed) - embed = self._add_trait_fields(embed) return self._add_comment_field(embed) async def display(self) -> None: