Compare commits
43 Commits
Author | SHA1 | Date | |
---|---|---|---|
7bd74af1ad | |||
d85ee1758f | |||
ec4ac13231 | |||
b0e352444b | |||
5faebfe556 | |||
25ba94b9ac | |||
be9c726fa0 | |||
fb8d8f033b | |||
b7f61d9485 | |||
5cdb12e8a8 | |||
b35d666218 | |||
461d176ce4 | |||
f0488690b7 | |||
3282ebaefa | |||
0d3e33d960 | |||
1782ffcffb | |||
319d5b20eb | |||
0c25dd4ffe | |||
11e5ee5c24 | |||
2690eb8760 | |||
0726a8db9e | |||
1e48bd16b3 | |||
3e7dabc94e | |||
f2f34bfbc6 | |||
ca03caf3ba | |||
f2318ed308 | |||
8b187ec2b3 | |||
b6f5fe9364 | |||
23a2b4c0cf | |||
b3df257103 | |||
223c20e792 | |||
ca57fae19d | |||
9ca6561bc3 | |||
700ba16186 | |||
5fd599338f | |||
fb3f3ee5e8 | |||
ebb5f2e7d3 | |||
685606fdb6 | |||
7e63607836 | |||
62599ea72c | |||
84eebfd848 | |||
762fa9acd4 | |||
d697c50268 |
@ -45,3 +45,5 @@ build-deb:
|
|||||||
paths:
|
paths:
|
||||||
- build/*.deb
|
- build/*.deb
|
||||||
expire_in: 1 week
|
expire_in: 1 week
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least
|
|||||||
the "copyright" line and a pointer to where the full notice is found.
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
Squirrel Battle
|
Squirrel Battle
|
||||||
Copyright (C) 2020 ynerant
|
Copyright (C) 2020 ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
This program is free software: you can redistribute it and/or modify
|
||||||
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
||||||
@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail.
|
|||||||
If the program does terminal interaction, make it output a short
|
If the program does terminal interaction, make it output a short
|
||||||
notice like this when it starts in an interactive mode:
|
notice like this when it starts in an interactive mode:
|
||||||
|
|
||||||
Squirrel Battle Copyright (C) 2020 ynerant
|
Squirrel Battle Copyright (C) 2020 ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
This is free software, and you are welcome to redistribute it
|
This is free software, and you are welcome to redistribute it
|
||||||
under certain conditions; type `show c' for details.
|
under certain conditions; type `show c' for details.
|
@ -1,7 +1,7 @@
|
|||||||
[](https://gitlab.crans.org/ynerant/squirrel-battle/-/commits/master)
|
[](https://gitlab.crans.org/ynerant/squirrel-battle/-/commits/master)
|
||||||
[](https://gitlab.crans.org/ynerant/squirrel-battle/-/commits/master)
|
[](https://gitlab.crans.org/ynerant/squirrel-battle/-/commits/master)
|
||||||
[](https://squirrel-battle.readthedocs.io/fr/latest/?badge=latest)
|
[](https://squirrel-battle.readthedocs.io/fr/latest/?badge=latest)
|
||||||
[](https://pypi.org/project/squirrel-battle/)
|
[](https://pypi.org/project/squirrel-battle/)
|
||||||
[](https://pypi.org/project/squirrel-battle/)
|
[](https://pypi.org/project/squirrel-battle/)
|
||||||
[](https://aur.archlinux.org/packages/python-squirrel-battle/)
|
[](https://aur.archlinux.org/packages/python-squirrel-battle/)
|
||||||
[](https://www.gnu.org/licenses/gpl-3.0.txt)
|
[](https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||||
|
2
debian/README.debian
vendored
2
debian/README.debian
vendored
@ -2,4 +2,4 @@ Squirrel Battle
|
|||||||
|
|
||||||
Watch out for squirrel's knifes!
|
Watch out for squirrel's knifes!
|
||||||
|
|
||||||
-- Yohann D'ANELLO <ynerant@crans.org> Thu, 19 Nov 2020 03:30:42 +0100
|
-- Yohann D'ANELLO <squirrel-battle@crans.org> Thu, 19 Nov 2020 03:30:42 +0100
|
||||||
|
8
debian/changelog
vendored
8
debian/changelog
vendored
@ -1,5 +1,11 @@
|
|||||||
python3-squirrel-battle (3.14) beta; urgency=low
|
python3-squirrel-battle (3.14) beta; urgency=low
|
||||||
|
|
||||||
|
* Some graphical improvements.
|
||||||
|
|
||||||
|
-- Yohann D'ANELLO <squirrel-battle@crans.org> Thu, 27 Nov 2020 18:25:42 +0100
|
||||||
|
|
||||||
|
python3-squirrel-battle (3.14) beta; urgency=low
|
||||||
|
|
||||||
* Initial release.
|
* Initial release.
|
||||||
|
|
||||||
-- Yohann D'ANELLO <ynerant@crans.org> Thu, 19 Nov 2020 03:30:42 +0100
|
-- Yohann D'ANELLO <squirrel-battle@crans.org> Thu, 19 Nov 2020 03:30:42 +0100
|
||||||
|
2
debian/control
vendored
2
debian/control
vendored
@ -1,7 +1,7 @@
|
|||||||
Source: python3-squirrel-battle
|
Source: python3-squirrel-battle
|
||||||
Section: devel
|
Section: devel
|
||||||
Priority: optional
|
Priority: optional
|
||||||
Maintainer: ynerant <ynrant@crans.org>
|
Maintainer: ynerant <squirrel-battle@crans.org>
|
||||||
Build-Depends: debhelper (>=10~), dh-python, python3-all, python3-setuptools
|
Build-Depends: debhelper (>=10~), dh-python, python3-all, python3-setuptools
|
||||||
Depends: fonts-noto-color-emoji
|
Depends: fonts-noto-color-emoji
|
||||||
Standards-Version: 4.1.4
|
Standards-Version: 4.1.4
|
||||||
|
6
debian/copyright
vendored
6
debian/copyright
vendored
@ -1,11 +1,11 @@
|
|||||||
|
|
||||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
Upstream-Name: Yohann D'ANELLO
|
Upstream-Name: ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
Upstream-Contact: Yohann D'ANELLO <ynerant@crans.org>
|
Upstream-Contact: ÿnérant, eichhornchen, nicomarg, charlse <squirrel-battle@crans.org>
|
||||||
Source: https://gitlab.crans.org/ynerant/squirrel-battle
|
Source: https://gitlab.crans.org/ynerant/squirrel-battle
|
||||||
|
|
||||||
Files: *
|
Files: *
|
||||||
Copyright: 2020 Yohann D'ANELLO <ynerant@crans.org>
|
Copyright: 2020 ÿnérant, eichhornchen, nicomarg, charlse <squirrel-battle@crans.org>
|
||||||
License: GPL-3+
|
License: GPL-3+
|
||||||
This program is free software; you can redistribute it
|
This program is free software; you can redistribute it
|
||||||
and/or modify it under the terms of the GNU General Public
|
and/or modify it under the terms of the GNU General Public
|
||||||
|
311
docs/deployment.rst
Normal file
311
docs/deployment.rst
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
Déploiement du projet
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. _PyPI: https://pypi.org/project/squirrel-battle/
|
||||||
|
.. _AUR: https://aur.archlinux.org/packages/python-squirrel-battle/
|
||||||
|
.. _Debian: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14.1_all.deb?job=build-deb
|
||||||
|
.. _installation: install.html
|
||||||
|
|
||||||
|
À chaque nouvelle version du projet, il est compilé et déployé dans PyPI_, dans
|
||||||
|
l'AUR_ et un paquet Debian_ est créé, voir la page d'installation_.
|
||||||
|
|
||||||
|
|
||||||
|
PyPI
|
||||||
|
----
|
||||||
|
|
||||||
|
Définition du paquet
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. _setup.py: https://gitlab.crans.org/ynerant/squirrel-battle/-/blob/master/setup.py
|
||||||
|
|
||||||
|
La documentation sur le packaging dans PyPI_ est disponible `ici
|
||||||
|
<https://packaging.python.org/tutorials/packaging-projects/>`_.
|
||||||
|
|
||||||
|
Le fichier `setup.py`_ contient l'ensemble des instructions d'installation du
|
||||||
|
paquet ainsi que des détails à fournir à PyPI :
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import os
|
||||||
|
|
||||||
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
with open("README.md", "r") as f:
|
||||||
|
long_description = f.read()
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="squirrel-battle",
|
||||||
|
version="3.14.1",
|
||||||
|
author="ÿnérant, eichhornchen, nicomarg, charlse",
|
||||||
|
author_email="squirrel-battle@crans.org",
|
||||||
|
description="Watch out for squirrel's knives!",
|
||||||
|
long_description=long_description,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
|
url="https://gitlab.crans.org/ynerant/squirrel-battle",
|
||||||
|
packages=find_packages(),
|
||||||
|
license='GPLv3',
|
||||||
|
classifiers=[
|
||||||
|
"Development Status :: 4 - Beta",
|
||||||
|
"Environment :: Console :: Curses",
|
||||||
|
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
|
||||||
|
"Natural Language :: French",
|
||||||
|
"Operating System :: OS Independent",
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"Programming Language :: Python :: 3.6",
|
||||||
|
"Programming Language :: Python :: 3.7",
|
||||||
|
"Programming Language :: Python :: 3.8",
|
||||||
|
"Programming Language :: Python :: 3.9",
|
||||||
|
"Topic :: Games/Entertainment",
|
||||||
|
],
|
||||||
|
python_requires='>=3.6',
|
||||||
|
include_package_data=True,
|
||||||
|
package_data={"squirrelbattle": ["assets/*"]},
|
||||||
|
entry_points={
|
||||||
|
"console_scripts": [
|
||||||
|
"squirrel-battle = squirrelbattle.bootstrap:Bootstrap.run_game",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
Ce fichier contient le nom du paquet, sa version, l'auteur et son contact,
|
||||||
|
sa description en une ligne et sa description longue, le lien d'accueil du projet,
|
||||||
|
sa licence, ses classificateurs et son exécutable.
|
||||||
|
|
||||||
|
Le paramètre ``entry_points`` définit un exécutable nommé ``squirrel-battle``,
|
||||||
|
qui permet de lancer le jeu.
|
||||||
|
|
||||||
|
|
||||||
|
Installation locale du paquet
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
L'installation du paquet localement dans son environnement Python (virtuel ou non)
|
||||||
|
peut se faire en exécutant ``pip install -e .``.
|
||||||
|
|
||||||
|
|
||||||
|
Génération des binaires
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Les paquets ``setuptools`` (``python3-setuptools`` pour APT, ``python-setuptools``
|
||||||
|
pour pacman) et ``wheel`` (``python3-wheel`` pour APT, ``python-wheel`` pour pacman)
|
||||||
|
sont nécessaires. Une fois installés, il faut appeler la commande :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
python3 setup.py sdist bdist_wheel
|
||||||
|
|
||||||
|
Une fois cela fait, le dossier ``dist/`` contiendra les archives à transmettre à PyPI.
|
||||||
|
|
||||||
|
|
||||||
|
Publier sur PyPI
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Il faut avant tout avoir un compte sur PyPI. Dans `votre compte PyPI
|
||||||
|
<https://pypi.org/manage/account/>`_, il faut générer un jeton d'accès API.
|
||||||
|
|
||||||
|
Dans le fichier ``.pypirc`` dans le répertoire principal de l'utilisateur,
|
||||||
|
il faut ajouter le jeton d'accès :
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
[pypi]
|
||||||
|
username = __token__
|
||||||
|
password = pypi-my-pypi-api-access-token
|
||||||
|
|
||||||
|
Cela permet de s'authentifier directement par ce jeton.
|
||||||
|
|
||||||
|
Ensuite, il faut installer ``twine``, qui permet de publier sur PyPI.
|
||||||
|
|
||||||
|
Il suffit ensuite d'appeler :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
twine upload dist/*
|
||||||
|
|
||||||
|
pour envoyer le paquet sur PyPI.
|
||||||
|
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
À des fins de tests, il est possible d'utiliser le dépôt `<https://test.pypi.org>`_.
|
||||||
|
Les différences sont au niveau de l'authentification, où il faut l'en-tête
|
||||||
|
``[testpypi]`` dans le ``.pypirc``, et il faut envoyer le paquet avec
|
||||||
|
``twine upload --repository testpypi dist/``.
|
||||||
|
|
||||||
|
|
||||||
|
Publier dans l'AUR
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Fonctionnement du packaging
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. _python-squirrel-battle: https://aur.archlinux.org/packages/python-squirrel-battle/
|
||||||
|
.. _python-squirrel-battle-git: https://aur.archlinux.org/packages/python-squirrel-battle-git/
|
||||||
|
|
||||||
|
Deux paquets sont publiés dans l'AUR (Arch User Repository) :
|
||||||
|
|
||||||
|
- python-squirrel-battle_
|
||||||
|
- python-squirrel-battle-git_
|
||||||
|
|
||||||
|
Le packaging dans Arch Linux se fait en commitant un fichier ``PKGBUILD`` dans
|
||||||
|
le dépôt à l'adresse ``ssh://aur@aur.archlinux.org/packagename.git``,
|
||||||
|
en remplaçant ``packagename`` par le nom du paquet.
|
||||||
|
|
||||||
|
Le second paquet compile directement le jeu à partir de la branche ``master``
|
||||||
|
du dépôt Git. Le fichier ``PKGBUILD`` dispose de cette structure :
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
# Maintainer: Yohann D'ANELLO <squirrel-battle@crans.org>
|
||||||
|
|
||||||
|
pkgbase=squirrel-battle
|
||||||
|
pkgname=python-squirrel-battle-git
|
||||||
|
pkgver=3.14.1
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Watch out for squirrel's knives!"
|
||||||
|
arch=('any')
|
||||||
|
url="https://gitlab.crans.org/ynerant/squirrel-battle"
|
||||||
|
license=('GPLv3')
|
||||||
|
depends=('python')
|
||||||
|
makedepends=('python-setuptools')
|
||||||
|
depends=('noto-fonts-emoji')
|
||||||
|
checkdepends=('python-tox')
|
||||||
|
ssource=("git+https://gitlab.crans.org/ynerant/squirrel-battle.git")
|
||||||
|
sha256sums=("SKIP")
|
||||||
|
|
||||||
|
pkgver() {
|
||||||
|
cd pkgbase
|
||||||
|
git describe --long --tags | sed -r 's/^v//;s/([^-]*-g)/r\1/;s/-/./g'
|
||||||
|
}
|
||||||
|
build() {
|
||||||
|
cd $pkgbase
|
||||||
|
python setup.py build
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
cd $pkgbase
|
||||||
|
tox -e py3
|
||||||
|
tox -e linters
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd $pkgbase
|
||||||
|
python setup.py install --skip-build \
|
||||||
|
--optimize=1 \
|
||||||
|
--root="${pkgdir}"
|
||||||
|
install -vDm 644 README.md \
|
||||||
|
-t "${pkgdir}/usr/share/doc/${pkgname}"
|
||||||
|
install -vDm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Ces instructions permettent de cloner le dépôt, l'installer et exécuter des tests,
|
||||||
|
en plus de définir les attributs du paquet.
|
||||||
|
|
||||||
|
Le fichier ``PKGBUILD`` du paquet ``python-squirrel-battle``, synchronisé avec
|
||||||
|
les releases, est plus ou moins similaire :
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
# Maintainer: Yohann D'ANELLO <squirrel-battle@crans.org>
|
||||||
|
|
||||||
|
pkgbase=squirrel-battle
|
||||||
|
pkgname=python-squirrel-battle
|
||||||
|
pkgver=3.14.1
|
||||||
|
pkgrel=1
|
||||||
|
pkgdesc="Watch out for squirrel's knives!"
|
||||||
|
arch=('any')
|
||||||
|
url="https://gitlab.crans.org/ynerant/squirrel-battle"
|
||||||
|
license=('GPLv3')
|
||||||
|
depends=('python')
|
||||||
|
makedepends=('python-setuptools')
|
||||||
|
depends=('noto-fonts-emoji')
|
||||||
|
checkdepends=('python-tox')
|
||||||
|
source=("https://gitlab.crans.org/ynerant/squirrel-battle/-/archive/v3.14.1/$pkgbase-v$pkgver.tar.gz")
|
||||||
|
sha256sums=("6090534d598c0b3a8f5acdb553c12908ba8107d62d08e17747d1dbb397bddef0")
|
||||||
|
|
||||||
|
build() {
|
||||||
|
cd $pkgbase-v$pkgver
|
||||||
|
python setup.py build
|
||||||
|
}
|
||||||
|
|
||||||
|
check() {
|
||||||
|
cd $pkgbase-v$pkgver
|
||||||
|
tox -e py3
|
||||||
|
tox -e linters
|
||||||
|
}
|
||||||
|
|
||||||
|
package() {
|
||||||
|
cd $pkgbase-v$pkgver
|
||||||
|
python setup.py install --skip-build \
|
||||||
|
--optimize=1 \
|
||||||
|
--root="${pkgdir}"
|
||||||
|
install -vDm 644 README.md \
|
||||||
|
-t "${pkgdir}/usr/share/doc/${pkgname}"
|
||||||
|
install -vDm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}"
|
||||||
|
}
|
||||||
|
|
||||||
|
Il se contente ici de télécharger l'archive de la dernière release, et de travailler
|
||||||
|
dessus.
|
||||||
|
|
||||||
|
|
||||||
|
Mettre à jour
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Pour mettre à jour le dépôt, une fois les dépôts
|
||||||
|
``ssh://aur@aur.archlinux.org/python-squirrel-battle.git`` et
|
||||||
|
``ssh://aur@aur.archlinux.org/python-squirrel-battle-git.git`` clonés,
|
||||||
|
il suffit de mettre à jour le paramètre ``pkgver`` pour la bonne version,
|
||||||
|
de régénérer le fichier ``.SRCINFO`` en faisant
|
||||||
|
``makepkg --printsrcinfo > .SRCINFO``, puis de committer/pousser.
|
||||||
|
|
||||||
|
|
||||||
|
Construction du paquet Debian
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
Structure du paquet
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
L'ensemble des instructions pour construire le paquet Debian est situé dans le
|
||||||
|
dossier ``debian/``.
|
||||||
|
|
||||||
|
Le fichier ``changelog`` est à modifier à chaque nouvelle version, le fichier
|
||||||
|
``compat`` contient la version minimale de Debian requise (``10`` pour Debian
|
||||||
|
Buster), le fichier ``copyright`` contient la liste des fichiers distribués sous
|
||||||
|
quelle licence (ici GPLv3), le fichier ``control`` contient les informations du
|
||||||
|
paquet, le fichier ``install`` les fichiers de configuration à installer
|
||||||
|
(ici le fix de l'affichage de l'écurueil), et enfin le fichier ``rules`` l'ensemble
|
||||||
|
des instructions à exécuter pour installer.
|
||||||
|
|
||||||
|
Le paquet ``fonts-noto-color-emoji`` est en dépendance pour le bon affichage
|
||||||
|
des émojis.
|
||||||
|
|
||||||
|
Mettre à jour le paquet
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Pour changer la version du paquet, il faut ajouter des lignes dans le fichier
|
||||||
|
``changelog``.
|
||||||
|
|
||||||
|
|
||||||
|
Construire le paquet
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
Il faut partir d'une installation de Debian.
|
||||||
|
|
||||||
|
D'abord on installe les paquets nécessaires :
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt --no-install-recommends install build-essential debmake dh-python debhelper python3-all python3-setuptools
|
||||||
|
|
||||||
|
On peut ensuite construire le paquet :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
dpkg-buildpackage
|
||||||
|
mkdir build && cp ../*.deb build/
|
||||||
|
|
||||||
|
Le paquet sera installé dans ``build/python3-squirrel-battle_3.14.1_all.deb``.
|
||||||
|
|
||||||
|
Le paquet Debian_ est construit par l'intégration continue Gitlab et ajouté
|
||||||
|
à chaque release.
|
31
docs/documentation.rst
Normal file
31
docs/documentation.rst
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
Documentation
|
||||||
|
=============
|
||||||
|
|
||||||
|
La documentation est gérée grâce à Sphinx. Le thème est le thème officiel de
|
||||||
|
ReadTheDocs ``sphinx-rtd-theme``.
|
||||||
|
|
||||||
|
Générer localement la documentation
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
On commence par se rendre au bon endroit et installer les bonnes dépendances :
|
||||||
|
|
||||||
|
.. code:: bash
|
||||||
|
|
||||||
|
cd docs
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
La documentation se génère à partir d'appels à ``make``, selon le type de
|
||||||
|
documentation voulue.
|
||||||
|
|
||||||
|
Par exemple, ``make html`` construit la documentation web, ``make latexpdf``
|
||||||
|
construit un livre PDF avec cette documentation.
|
||||||
|
|
||||||
|
|
||||||
|
Documentation externe
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
À chaque commit, un webhook est envoyé à `<readthedocs.io>`_, qui construit
|
||||||
|
tout seul la documentation Sphinx, la publiant à l'adresse
|
||||||
|
`<squirrel-battle.readthedocs.io>`_.
|
||||||
|
|
||||||
|
De plus, les documentations sont sauvegardées à chaque release taguée.
|
@ -25,14 +25,14 @@ Dans le `pack de textures`_ ASCII, il est représenté par le caractère ``*``.
|
|||||||
Dans le `pack de textures`_ écureuil, il est représenté par l'émoji ``🦔``.
|
Dans le `pack de textures`_ écureuil, il est représenté par l'émoji ``🦔``.
|
||||||
|
|
||||||
|
|
||||||
Castor
|
Tigre
|
||||||
------
|
-----
|
||||||
|
|
||||||
Son nom est fixé à `beaver`. Il a par défaut une force à **2** et **20** points de vie.
|
Son nom est fixé à `tiger`. Il a par défaut une force à **2** et **20** points de vie.
|
||||||
|
|
||||||
Dans le `pack de textures`_ ASCII, il est représenté par le caractère ``_``.
|
Dans le `pack de textures`_ ASCII, il est représenté par le caractère ``n``.
|
||||||
|
|
||||||
Dans le `pack de textures`_ écureuil, il est représenté par l'émoji ``🦫``.
|
Dans le `pack de textures`_ écureuil, il est représenté par l'émoji ``🐅``.
|
||||||
|
|
||||||
|
|
||||||
Lapin
|
Lapin
|
||||||
|
@ -13,11 +13,11 @@ Bienvenue dans la documentation de Squirrel Battle !
|
|||||||
:target: https://squirrel-battle.readthedocs.io/fr/latest/?badge=latest
|
:target: https://squirrel-battle.readthedocs.io/fr/latest/?badge=latest
|
||||||
:alt: Documentation Status
|
:alt: Documentation Status
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/dungeon-battle
|
.. image:: https://img.shields.io/pypi/v/squirrel-battle
|
||||||
:target: https://pypi.org/project/squirrel-battle/
|
:target: https://pypi.org/project/squirrel-battle/
|
||||||
:alt: PyPI
|
:alt: PyPI
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/dm/dungeon-battle
|
.. image:: https://img.shields.io/pypi/dm/squirrel-battle
|
||||||
:target: https://pypi.org/project/squirrel-battle/
|
:target: https://pypi.org/project/squirrel-battle/
|
||||||
:alt: PyPI downloads
|
:alt: PyPI downloads
|
||||||
|
|
||||||
@ -37,6 +37,8 @@ Bienvenue dans la documentation de Squirrel Battle !
|
|||||||
install-dev
|
install-dev
|
||||||
tests
|
tests
|
||||||
display/index
|
display/index
|
||||||
|
deployment
|
||||||
|
documentation
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 3
|
:maxdepth: 3
|
||||||
|
@ -61,29 +61,19 @@ Le jeu peut être ensuite lancé via la commande ``squirrel-battle``.
|
|||||||
Sur Ubuntu/Debian
|
Sur Ubuntu/Debian
|
||||||
~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. _paquet: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14_all.deb?job=build-deb
|
.. _paquet: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14.1_all.deb?job=build-deb
|
||||||
|
|
||||||
Un paquet_ est généré par l'intégration continue de Gitlab à chaque commit.
|
Un paquet_ est généré par l'intégration continue de Gitlab à chaque commit.
|
||||||
Ils sont également attachés à chaque nouvelle release.
|
Ils sont également attachés à chaque nouvelle release.
|
||||||
|
|
||||||
Il dépend du paquet ``fonts-noto-color-emoji``, permettant d'afficher les émojis
|
Il dépend du paquet ``fonts-noto-color-emoji``, permettant d'afficher les émojis
|
||||||
dans le terminal. Il peut être installé via APT normalement sur une distribution
|
dans le terminal. Il peut être installé via APT.
|
||||||
récente, toutefois sur les versions les plus vieilles, incluant Debian Buster,
|
|
||||||
certains émojis n'apparaissent pas. Il est essentiel de maintenir ce paquet à
|
|
||||||
jour. Pour installer manuellement la dernière version de ce paquet,
|
|
||||||
il suffit d'exécuter :
|
|
||||||
|
|
||||||
.. code:: bash
|
|
||||||
|
|
||||||
wget http://ftp.fr.debian.org/debian/pool/main/f/fonts-noto-color-emoji/fonts-noto-color-emoji_0~20200916-1_all.deb
|
|
||||||
dpkg -i fonts-noto-color-emoji_0~20200916-1_all.deb
|
|
||||||
rm fonts-noto-color-emoji_0~20200916-1_all.deb
|
|
||||||
|
|
||||||
Pour installer ce paquet, il suffit de le télécharger et d'appeler ``dpkg`` :
|
Pour installer ce paquet, il suffit de le télécharger et d'appeler ``dpkg`` :
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
dpkg -i python3-squirrelbattle_3.14_all.deb
|
dpkg -i python3-squirrelbattle_3.14.1_all.deb
|
||||||
|
|
||||||
Ce paquet inclut un patch pour afficher les émojis écureuil correctement.
|
Ce paquet inclut un patch pour afficher les émojis écureuil correctement.
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ Pack de textures
|
|||||||
.. _Cœur: entities/items.html#coeur
|
.. _Cœur: entities/items.html#coeur
|
||||||
.. _Bombe: entities/items.html#bombe
|
.. _Bombe: entities/items.html#bombe
|
||||||
.. _Lapin: entities/monsters.html#lapin
|
.. _Lapin: entities/monsters.html#lapin
|
||||||
.. _Castor: entities/monsters.html#castor
|
.. _Tigre: entities/monsters.html#tigre
|
||||||
.. _Nounours: entities/monsters.html#nounours
|
.. _Nounours: entities/monsters.html#nounours
|
||||||
|
|
||||||
Chaque entité_ et chaque tuile_ de la carte_ est associé à un caractère pour
|
Chaque entité_ et chaque tuile_ de la carte_ est associé à un caractère pour
|
||||||
@ -42,7 +42,7 @@ Chaque tuile fait un caractère de large.
|
|||||||
* Cœur_ : ``❤``
|
* Cœur_ : ``❤``
|
||||||
* Bombe_ : ``o``
|
* Bombe_ : ``o``
|
||||||
* Lapin_ : ``Y``
|
* Lapin_ : ``Y``
|
||||||
* Castor_ : ``_``
|
* Tigre_ : ``n``
|
||||||
* Nounours_ : ``8``
|
* Nounours_ : ``8``
|
||||||
|
|
||||||
|
|
||||||
@ -61,5 +61,5 @@ Chaque tuile fait 2 caractères de large pour afficher les émojis proprement.
|
|||||||
* Cœur_ : ``💜``
|
* Cœur_ : ``💜``
|
||||||
* Bombe_ : ``💣``
|
* Bombe_ : ``💣``
|
||||||
* Lapin_ : ``🐇``
|
* Lapin_ : ``🐇``
|
||||||
* Castor_ : ``🦫``
|
* Tigre_ : ``🐅``
|
||||||
* Nounours_ : ``🧸``
|
* Nounours_ : ``🧸``
|
||||||
|
@ -24,21 +24,12 @@ Sous Ubuntu/Debian
|
|||||||
^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
À nouveau, le terminal `xfce4-terminal` est recommandé. Le paquet
|
À nouveau, le terminal `xfce4-terminal` est recommandé. Le paquet
|
||||||
`fonts-noto-color-emoji`. Toutefois, le rythme de mise à jour de Debian étant
|
`fonts-noto-color-emoji`.
|
||||||
lent, le paquet le plus récent ne contient pas tous les émojis. Sur Debian,
|
|
||||||
il faudra donc installer le paquet le plus récent, ce qui fonctionne sans
|
|
||||||
dépendance supplémentaire :
|
|
||||||
|
|
||||||
.. code:: bash
|
Toutefois, un problème reste avec l'écureuil. Sous Ubuntu et Debian, le
|
||||||
|
caractère écureuil existe déjà, mais ne s'affiche pas proprement. On peut
|
||||||
wget http://ftp.fr.debian.org/debian/pool/main/f/fonts-noto-color-emoji/fonts-noto-color-emoji_0~20200916-1_all.deb
|
appliquer un patch qui permet d'afficher les émojis correctement dans son
|
||||||
dpkg -i fonts-noto-color-emoji_0~20200916-1_all.deb
|
terminal. Pour cela, il suffit de faire :
|
||||||
rm fonts-noto-color-emoji_0~20200916-1_all.deb
|
|
||||||
|
|
||||||
Il reste le problème de l'écureuil. Sous Ubuntu et Debian, le caractère écureuil
|
|
||||||
existe déjà, mais ne s'affiche pas proprement. On peut appliquer un patch qui
|
|
||||||
permet d'afficher les émojis correctement dans son terminal. Pour cela, il
|
|
||||||
suffit de faire :
|
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
|
6
main.py
6
main.py
@ -1,4 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from squirrelbattle.bootstrap import Bootstrap
|
from squirrelbattle.bootstrap import Bootstrap
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
12
setup.py
12
setup.py
@ -1,4 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
@ -8,10 +12,10 @@ with open("README.md", "r") as f:
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="squirrel-battle",
|
name="squirrel-battle",
|
||||||
version="3.14",
|
version="3.14.1",
|
||||||
author="ynerant",
|
author="ÿnérant, eichhornchen, nicomarg, charlse",
|
||||||
author_email="ynerant@crans.org",
|
author_email="squirrel-battle@crans.org",
|
||||||
description="Watch out for squirrel's knifes!",
|
description="Watch out for squirrel's knives!",
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
long_description_content_type="text/markdown",
|
long_description_content_type="text/markdown",
|
||||||
url="https://gitlab.crans.org/ynerant/squirrel-battle",
|
url="https://gitlab.crans.org/ynerant/squirrel-battle",
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from squirrelbattle.game import Game
|
from squirrelbattle.game import Game
|
||||||
from squirrelbattle.display.display_manager import DisplayManager
|
from squirrelbattle.display.display_manager import DisplayManager
|
||||||
from squirrelbattle.term_manager import TermManager
|
from squirrelbattle.term_manager import TermManager
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
from typing import Any, Optional, Union
|
from typing import Any, Optional, Union
|
||||||
|
|
||||||
@ -19,6 +22,24 @@ class Display:
|
|||||||
def newpad(self, height: int, width: int) -> Union[FakePad, Any]:
|
def newpad(self, height: int, width: int) -> Union[FakePad, Any]:
|
||||||
return curses.newpad(height, width) if self.screen else FakePad()
|
return curses.newpad(height, width) if self.screen else FakePad()
|
||||||
|
|
||||||
|
def truncate(self, msg: str, height: int, width: int) -> str:
|
||||||
|
height = max(0, height)
|
||||||
|
width = max(0, width)
|
||||||
|
lines = msg.split("\n")
|
||||||
|
lines = lines[:height]
|
||||||
|
lines = [line[:width] for line in lines]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
def addstr(self, pad: Any, y: int, x: int, msg: str, *options) -> None:
|
||||||
|
"""
|
||||||
|
Display a message onto the pad.
|
||||||
|
If the message is too large, it is truncated vertically and horizontally
|
||||||
|
"""
|
||||||
|
height, width = pad.getmaxyx()
|
||||||
|
msg = self.truncate(msg, height - y, width - x - 1)
|
||||||
|
if msg.replace("\n", "") and x >= 0 and y >= 0:
|
||||||
|
return pad.addstr(y, x, msg, *options)
|
||||||
|
|
||||||
def init_pair(self, number: int, foreground: int, background: int) -> None:
|
def init_pair(self, number: int, foreground: int, background: int) -> None:
|
||||||
return curses.init_pair(number, foreground, background) \
|
return curses.init_pair(number, foreground, background) \
|
||||||
if self.screen else None
|
if self.screen else None
|
||||||
@ -32,14 +53,36 @@ class Display:
|
|||||||
self.y = y
|
self.y = y
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
if hasattr(self, "pad") and resize_pad:
|
if hasattr(self, "pad") and resize_pad and \
|
||||||
self.pad.resize(self.height, self.width)
|
self.height >= 0 and self.width >= 0:
|
||||||
|
self.pad.resize(self.height + 1, self.width + 1)
|
||||||
|
|
||||||
def refresh(self, *args, resize_pad: bool = True) -> None:
|
def refresh(self, *args, resize_pad: bool = True) -> None:
|
||||||
if len(args) == 4:
|
if len(args) == 4:
|
||||||
self.resize(*args, resize_pad)
|
self.resize(*args, resize_pad)
|
||||||
self.display()
|
self.display()
|
||||||
|
|
||||||
|
def refresh_pad(self, pad: Any, top_y: int, top_x: int,
|
||||||
|
window_y: int, window_x: int,
|
||||||
|
last_y: int, last_x: int) -> None:
|
||||||
|
"""
|
||||||
|
Refresh a pad on a part of the window.
|
||||||
|
The refresh starts at coordinates (top_y, top_x) from the pad,
|
||||||
|
and is drawn from (window_y, window_x) to (last_y, last_x).
|
||||||
|
If coordinates are invalid (negative indexes/length..., then nothing
|
||||||
|
is drawn and no error is raised.
|
||||||
|
"""
|
||||||
|
top_y, top_x = max(0, top_y), max(0, top_x)
|
||||||
|
window_y, window_x = max(0, window_y), max(0, window_x)
|
||||||
|
screen_max_y, screen_max_x = self.screen.getmaxyx() if self.screen \
|
||||||
|
else (42, 42)
|
||||||
|
last_y, last_x = min(screen_max_y - 1, last_y), \
|
||||||
|
min(screen_max_x - 1, last_x)
|
||||||
|
|
||||||
|
if last_y >= window_y and last_x >= window_x:
|
||||||
|
# Refresh the pad only if coordinates are valid
|
||||||
|
pad.refresh(top_y, top_x, window_y, window_x, last_y, last_x)
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
@ -50,3 +93,68 @@ class Display:
|
|||||||
@property
|
@property
|
||||||
def cols(self) -> int:
|
def cols(self) -> int:
|
||||||
return curses.COLS if self.screen else 42
|
return curses.COLS if self.screen else 42
|
||||||
|
|
||||||
|
|
||||||
|
class VerticalSplit(Display):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.pad = self.newpad(self.rows, 1)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@width.setter
|
||||||
|
def width(self, val: Any) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def display(self) -> None:
|
||||||
|
for i in range(self.height):
|
||||||
|
self.addstr(self.pad, i, 0, "┃")
|
||||||
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
|
self.y + self.height - 1, self.x)
|
||||||
|
|
||||||
|
|
||||||
|
class HorizontalSplit(Display):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.pad = self.newpad(1, self.cols)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@height.setter
|
||||||
|
def height(self, val: Any) -> None:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def display(self) -> None:
|
||||||
|
for i in range(self.width):
|
||||||
|
self.addstr(self.pad, 0, i, "━")
|
||||||
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.y,
|
||||||
|
self.x + self.width - 1)
|
||||||
|
|
||||||
|
|
||||||
|
class Box(Display):
|
||||||
|
|
||||||
|
def __init__(self, *args, fg_border_color: Optional[int] = None, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.pad = self.newpad(self.rows, self.cols)
|
||||||
|
self.fg_border_color = fg_border_color or curses.COLOR_WHITE
|
||||||
|
|
||||||
|
pair_number = 4 + self.fg_border_color
|
||||||
|
self.init_pair(pair_number, self.fg_border_color, curses.COLOR_BLACK)
|
||||||
|
self.pair = self.color_pair(pair_number)
|
||||||
|
|
||||||
|
def display(self) -> None:
|
||||||
|
self.addstr(self.pad, 0, 0, "┏" + "━" * (self.width - 2) + "┓",
|
||||||
|
self.pair)
|
||||||
|
for i in range(1, self.height - 1):
|
||||||
|
self.addstr(self.pad, i, 0, "┃", self.pair)
|
||||||
|
self.addstr(self.pad, i, self.width - 1, "┃", self.pair)
|
||||||
|
self.addstr(self.pad, self.height - 1, 0,
|
||||||
|
"┗" + "━" * (self.width - 2) + "┛", self.pair)
|
||||||
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
|
self.y + self.height - 1, self.x + self.width - 1)
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
|
from squirrelbattle.display.display import VerticalSplit, HorizontalSplit
|
||||||
from squirrelbattle.display.mapdisplay import MapDisplay
|
from squirrelbattle.display.mapdisplay import MapDisplay
|
||||||
|
from squirrelbattle.display.messagedisplay import MessageDisplay
|
||||||
from squirrelbattle.display.statsdisplay import StatsDisplay
|
from squirrelbattle.display.statsdisplay import StatsDisplay
|
||||||
from squirrelbattle.display.menudisplay import SettingsMenuDisplay, \
|
from squirrelbattle.display.menudisplay import SettingsMenuDisplay, \
|
||||||
MainMenuDisplay
|
MainMenuDisplay
|
||||||
@ -22,9 +27,12 @@ class DisplayManager:
|
|||||||
screen, pack)
|
screen, pack)
|
||||||
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
self.settingsmenudisplay = SettingsMenuDisplay(screen, pack)
|
||||||
self.logsdisplay = LogsDisplay(screen, pack)
|
self.logsdisplay = LogsDisplay(screen, pack)
|
||||||
|
self.messagedisplay = MessageDisplay(screen=screen, pack=None)
|
||||||
|
self.hbar = HorizontalSplit(screen, pack)
|
||||||
|
self.vbar = VerticalSplit(screen, pack)
|
||||||
self.displays = [self.statsdisplay, self.mapdisplay,
|
self.displays = [self.statsdisplay, self.mapdisplay,
|
||||||
self.mainmenudisplay, self.settingsmenudisplay,
|
self.mainmenudisplay, self.settingsmenudisplay,
|
||||||
self.logsdisplay]
|
self.logsdisplay, self.messagedisplay]
|
||||||
self.update_game_components()
|
self.update_game_components()
|
||||||
|
|
||||||
def handle_display_action(self, action: DisplayActions) -> None:
|
def handle_display_action(self, action: DisplayActions) -> None:
|
||||||
@ -40,20 +48,35 @@ class DisplayManager:
|
|||||||
self.statsdisplay.update_player(self.game.player)
|
self.statsdisplay.update_player(self.game.player)
|
||||||
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
self.settingsmenudisplay.update_menu(self.game.settings_menu)
|
||||||
self.logsdisplay.update_logs(self.game.logs)
|
self.logsdisplay.update_logs(self.game.logs)
|
||||||
|
self.messagedisplay.update_message(self.game.message)
|
||||||
|
|
||||||
def refresh(self) -> None:
|
def refresh(self) -> None:
|
||||||
if self.game.state == GameMode.PLAY:
|
if self.game.state == GameMode.PLAY:
|
||||||
# The map pad has already the good size
|
# The map pad has already the good size
|
||||||
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, self.cols,
|
self.mapdisplay.refresh(0, 0, self.rows * 4 // 5,
|
||||||
|
self.mapdisplay.pack.tile_width
|
||||||
|
* (self.cols * 4 // 5
|
||||||
|
// self.mapdisplay.pack.tile_width),
|
||||||
resize_pad=False)
|
resize_pad=False)
|
||||||
self.statsdisplay.refresh(self.rows * 4 // 5, 0,
|
self.statsdisplay.refresh(0, self.cols * 4 // 5 + 1,
|
||||||
self.rows // 10, self.cols)
|
self.rows, self.cols // 5 - 1)
|
||||||
self.logsdisplay.refresh(self.rows * 9 // 10, 0,
|
self.logsdisplay.refresh(self.rows * 4 // 5 + 1, 0,
|
||||||
self.rows // 10, self.cols)
|
self.rows // 5 - 1, self.cols * 4 // 5)
|
||||||
|
self.hbar.refresh(self.rows * 4 // 5, 0, 1, self.cols * 4 // 5)
|
||||||
|
self.vbar.refresh(0, self.cols * 4 // 5, self.rows, 1)
|
||||||
if self.game.state == GameMode.MAINMENU:
|
if self.game.state == GameMode.MAINMENU:
|
||||||
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
self.mainmenudisplay.refresh(0, 0, self.rows, self.cols)
|
||||||
if self.game.state == GameMode.SETTINGS:
|
if self.game.state == GameMode.SETTINGS:
|
||||||
self.settingsmenudisplay.refresh(0, 0, self.rows, self.cols - 1)
|
self.settingsmenudisplay.refresh(0, 0, self.rows, self.cols - 1)
|
||||||
|
|
||||||
|
if self.game.message:
|
||||||
|
height, width = 0, 0
|
||||||
|
for line in self.game.message.split("\n"):
|
||||||
|
height += 1
|
||||||
|
width = max(width, len(line))
|
||||||
|
y, x = (self.rows - height) // 2, (self.cols - width) // 2
|
||||||
|
self.messagedisplay.refresh(y, x, height, width)
|
||||||
|
|
||||||
self.resize_window()
|
self.resize_window()
|
||||||
|
|
||||||
def resize_window(self) -> bool:
|
def resize_window(self) -> bool:
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from squirrelbattle.display.display import Display
|
from squirrelbattle.display.display import Display
|
||||||
from squirrelbattle.interfaces import Logs
|
from squirrelbattle.interfaces import Logs
|
||||||
|
|
||||||
@ -12,12 +15,11 @@ class LogsDisplay(Display):
|
|||||||
self.logs = logs
|
self.logs = logs
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
print(type(self.logs.messages), flush=True)
|
|
||||||
messages = self.logs.messages[-self.height:]
|
messages = self.logs.messages[-self.height:]
|
||||||
messages = messages[::-1]
|
messages = messages[::-1]
|
||||||
self.pad.clear()
|
self.pad.erase()
|
||||||
for i in range(min(self.height, len(messages))):
|
for i in range(min(self.height, len(messages))):
|
||||||
self.pad.addstr(self.height - i - 1, self.x,
|
self.addstr(self.pad, self.height - i - 1, self.x,
|
||||||
messages[i][:self.width])
|
messages[i][:self.width])
|
||||||
self.pad.refresh(0, 0, self.y, self.x, self.y + self.height,
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
self.x + self.width)
|
self.y + self.height - 1, self.x + self.width - 1)
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from squirrelbattle.interfaces import Map
|
from squirrelbattle.interfaces import Map
|
||||||
from .display import Display
|
from .display import Display
|
||||||
|
|
||||||
@ -15,11 +17,11 @@ class MapDisplay(Display):
|
|||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
self.init_pair(1, self.pack.tile_fg_color, self.pack.tile_bg_color)
|
self.init_pair(1, self.pack.tile_fg_color, self.pack.tile_bg_color)
|
||||||
self.init_pair(2, self.pack.entity_fg_color, self.pack.entity_bg_color)
|
self.init_pair(2, self.pack.entity_fg_color, self.pack.entity_bg_color)
|
||||||
self.pad.addstr(0, 0, self.map.draw_string(self.pack),
|
self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack),
|
||||||
self.color_pair(1))
|
self.color_pair(1))
|
||||||
for e in self.map.entities:
|
for e in self.map.entities:
|
||||||
self.pad.addstr(e.y, self.pack.tile_width * e.x,
|
self.addstr(self.pad, e.y, self.pack.tile_width * e.x,
|
||||||
self.pack[e.name.upper()], self.color_pair(2))
|
self.pack[e.name.upper()], self.color_pair(2))
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
y, x = self.map.currenty, self.pack.tile_width * self.map.currentx
|
y, x = self.map.currenty, self.pack.tile_width * self.map.currentx
|
||||||
@ -31,9 +33,18 @@ class MapDisplay(Display):
|
|||||||
smaxrow = min(smaxrow, self.height - 1)
|
smaxrow = min(smaxrow, self.height - 1)
|
||||||
smaxcol = self.pack.tile_width * self.map.width - \
|
smaxcol = self.pack.tile_width * self.map.width - \
|
||||||
(x + deltax) + self.width - 1
|
(x + deltax) + self.width - 1
|
||||||
|
|
||||||
|
# Wrap perfectly the map according to the width of the tiles
|
||||||
|
pmincol = self.pack.tile_width * (pmincol // self.pack.tile_width)
|
||||||
|
smincol = self.pack.tile_width * (smincol // self.pack.tile_width)
|
||||||
|
smaxcol = self.pack.tile_width \
|
||||||
|
* (smaxcol // self.pack.tile_width + 1) - 1
|
||||||
|
|
||||||
smaxcol = min(smaxcol, self.width - 1)
|
smaxcol = min(smaxcol, self.width - 1)
|
||||||
pminrow = max(0, min(self.map.height, pminrow))
|
pminrow = max(0, min(self.map.height, pminrow))
|
||||||
pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol))
|
pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol))
|
||||||
self.pad.clear()
|
|
||||||
|
self.pad.erase()
|
||||||
self.update_pad()
|
self.update_pad()
|
||||||
self.pad.refresh(pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol)
|
self.refresh_pad(self.pad, pminrow, pmincol, sminrow, smincol, smaxrow,
|
||||||
|
smaxcol)
|
||||||
|
@ -1,16 +1,19 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from squirrelbattle.menus import Menu, MainMenu
|
from squirrelbattle.menus import Menu, MainMenu
|
||||||
from .display import Display
|
from .display import Display, Box
|
||||||
from ..resources import ResourceManager
|
from ..resources import ResourceManager
|
||||||
|
|
||||||
|
|
||||||
class MenuDisplay(Display):
|
class MenuDisplay(Display):
|
||||||
position: int
|
position: int
|
||||||
|
|
||||||
def __init__(self, *args):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args)
|
super().__init__(*args, **kwargs)
|
||||||
self.menubox = self.newpad(self.rows, self.cols)
|
self.menubox = Box(*args, **kwargs)
|
||||||
|
|
||||||
def update_menu(self, menu: Menu) -> None:
|
def update_menu(self, menu: Menu) -> None:
|
||||||
self.menu = menu
|
self.menu = menu
|
||||||
@ -20,13 +23,13 @@ class MenuDisplay(Display):
|
|||||||
# Menu values are printed in pad
|
# Menu values are printed in pad
|
||||||
self.pad = self.newpad(self.trueheight, self.truewidth + 2)
|
self.pad = self.newpad(self.trueheight, self.truewidth + 2)
|
||||||
for i in range(self.trueheight):
|
for i in range(self.trueheight):
|
||||||
self.pad.addstr(i, 0, " " + self.values[i])
|
self.addstr(self.pad, i, 0, " " + self.values[i])
|
||||||
|
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
for i in range(self.trueheight):
|
for i in range(self.trueheight):
|
||||||
self.pad.addstr(i, 0, " " + self.values[i])
|
self.addstr(self.pad, i, 0, " " + self.values[i])
|
||||||
# set a marker on the selected line
|
# set a marker on the selected line
|
||||||
self.pad.addstr(self.menu.position, 0, ">")
|
self.addstr(self.pad, self.menu.position, 0, ">")
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
cornery = 0 if self.height - 2 >= self.menu.position - 1 \
|
cornery = 0 if self.height - 2 >= self.menu.position - 1 \
|
||||||
@ -34,17 +37,10 @@ class MenuDisplay(Display):
|
|||||||
if self.height - 2 >= self.trueheight - self.menu.position else 0
|
if self.height - 2 >= self.trueheight - self.menu.position else 0
|
||||||
|
|
||||||
# Menu box
|
# Menu box
|
||||||
self.menubox.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓")
|
self.menubox.refresh(self.y, self.x, self.height, self.width)
|
||||||
for i in range(1, self.height - 1):
|
self.pad.erase()
|
||||||
self.menubox.addstr(i, 0, "┃" + " " * (self.width - 2) + "┃")
|
|
||||||
self.menubox.addstr(self.height - 1, 0,
|
|
||||||
"┗" + "━" * (self.width - 2) + "┛")
|
|
||||||
|
|
||||||
self.menubox.refresh(0, 0, self.y, self.x,
|
|
||||||
self.height + self.y,
|
|
||||||
self.width + self.x)
|
|
||||||
self.update_pad()
|
self.update_pad()
|
||||||
self.pad.refresh(cornery, 0, self.y + 1, self.x + 2,
|
self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 2,
|
||||||
self.height - 2 + self.y,
|
self.height - 2 + self.y,
|
||||||
self.width - 2 + self.x)
|
self.width - 2 + self.x)
|
||||||
|
|
||||||
@ -86,9 +82,11 @@ class MainMenuDisplay(Display):
|
|||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
for i in range(len(self.title)):
|
for i in range(len(self.title)):
|
||||||
self.pad.addstr(4 + i, max(self.width // 2
|
self.addstr(self.pad, 4 + i, max(self.width // 2
|
||||||
- len(self.title[0]) // 2 - 1, 0), self.title[i])
|
- len(self.title[0]) // 2 - 1, 0), self.title[i])
|
||||||
self.pad.refresh(0, 0, self.y, self.x, self.height, self.width)
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
|
self.height + self.y - 1,
|
||||||
|
self.width + self.x - 1)
|
||||||
menuwidth = min(self.menudisplay.preferred_width, self.width)
|
menuwidth = min(self.menudisplay.preferred_width, self.width)
|
||||||
menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
|
menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1
|
||||||
self.menudisplay.refresh(
|
self.menudisplay.refresh(
|
||||||
|
31
squirrelbattle/display/messagedisplay.py
Normal file
31
squirrelbattle/display/messagedisplay.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
import curses
|
||||||
|
|
||||||
|
from squirrelbattle.display.display import Box, Display
|
||||||
|
|
||||||
|
|
||||||
|
class MessageDisplay(Display):
|
||||||
|
"""
|
||||||
|
Display a message in a popup.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.box = Box(fg_border_color=curses.COLOR_RED, *args, **kwargs)
|
||||||
|
self.message = ""
|
||||||
|
self.pad = self.newpad(1, 1)
|
||||||
|
|
||||||
|
def update_message(self, msg: str) -> None:
|
||||||
|
self.message = msg
|
||||||
|
|
||||||
|
def display(self) -> None:
|
||||||
|
self.box.refresh(self.y - 1, self.x - 2,
|
||||||
|
self.height + 2, self.width + 4)
|
||||||
|
self.box.display()
|
||||||
|
self.pad.erase()
|
||||||
|
self.addstr(self.pad, 0, 0, self.message, curses.A_BOLD)
|
||||||
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
|
self.height + self.y - 1,
|
||||||
|
self.width + self.x - 1)
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
|
|
||||||
from .display import Display
|
from .display import Display
|
||||||
@ -17,36 +20,28 @@ class StatsDisplay(Display):
|
|||||||
self.player = p
|
self.player = p
|
||||||
|
|
||||||
def update_pad(self) -> None:
|
def update_pad(self) -> None:
|
||||||
string = ""
|
string2 = "Player -- LVL {}\nEXP {}/{}\nHP {}/{}"\
|
||||||
for _ in range(self.width - 1):
|
|
||||||
string = string + "-"
|
|
||||||
self.pad.addstr(0, 0, string)
|
|
||||||
string2 = "Player -- LVL {} EXP {}/{} HP {}/{}"\
|
|
||||||
.format(self.player.level, self.player.current_xp,
|
.format(self.player.level, self.player.current_xp,
|
||||||
self.player.max_xp, self.player.health,
|
self.player.max_xp, self.player.health,
|
||||||
self.player.maxhealth)
|
self.player.maxhealth)
|
||||||
for _ in range(self.width - len(string2) - 1):
|
self.addstr(self.pad, 0, 0, string2)
|
||||||
string2 = string2 + " "
|
string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}"\
|
||||||
self.pad.addstr(1, 0, string2)
|
|
||||||
string3 = "Stats : STR {} INT {} CHR {} DEX {} CON {}"\
|
|
||||||
.format(self.player.strength,
|
.format(self.player.strength,
|
||||||
self.player.intelligence, self.player.charisma,
|
self.player.intelligence, self.player.charisma,
|
||||||
self.player.dexterity, self.player.constitution)
|
self.player.dexterity, self.player.constitution)
|
||||||
for _ in range(self.width - len(string3) - 1):
|
self.addstr(self.pad, 3, 0, string3)
|
||||||
string3 = string3 + " "
|
|
||||||
self.pad.addstr(2, 0, string3)
|
|
||||||
|
|
||||||
inventory_str = "Inventaire : " + "".join(
|
inventory_str = "Inventaire : " + "".join(
|
||||||
self.pack[item.name.upper()] for item in self.player.inventory)
|
self.pack[item.name.upper()] for item in self.player.inventory)
|
||||||
self.pad.addstr(3, 0, inventory_str)
|
self.addstr(self.pad, 8, 0, inventory_str)
|
||||||
|
|
||||||
if self.player.dead:
|
if self.player.dead:
|
||||||
self.pad.addstr(4, 0, "VOUS ÊTES MORT",
|
self.addstr(self.pad, 10, 0, "VOUS ÊTES MORT",
|
||||||
curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT
|
curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT
|
||||||
| self.color_pair(3))
|
| self.color_pair(3))
|
||||||
|
|
||||||
def display(self) -> None:
|
def display(self) -> None:
|
||||||
self.pad.clear()
|
self.pad.erase()
|
||||||
self.update_pad()
|
self.update_pad()
|
||||||
self.pad.refresh(0, 0, self.y, self.x,
|
self.refresh_pad(self.pad, 0, 0, self.y, self.x,
|
||||||
4 + self.y, self.width + self.x)
|
self.y + self.height - 1, self.width + self.x - 1)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@ -51,7 +54,7 @@ TexturePack.ASCII_PACK = TexturePack(
|
|||||||
HEART='❤',
|
HEART='❤',
|
||||||
BOMB='o',
|
BOMB='o',
|
||||||
RABBIT='Y',
|
RABBIT='Y',
|
||||||
BEAVER='_',
|
TIGER='n',
|
||||||
TEDDY_BEAR='8',
|
TEDDY_BEAR='8',
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -65,11 +68,11 @@ TexturePack.SQUIRREL_PACK = TexturePack(
|
|||||||
EMPTY=' ',
|
EMPTY=' ',
|
||||||
WALL='🧱',
|
WALL='🧱',
|
||||||
FLOOR='██',
|
FLOOR='██',
|
||||||
PLAYER='🐿 ️',
|
PLAYER='🐿️ ️',
|
||||||
HEDGEHOG='🦔',
|
HEDGEHOG='🦔',
|
||||||
HEART='💜',
|
HEART='💜',
|
||||||
BOMB='💣',
|
BOMB='💣',
|
||||||
RABBIT='🐇',
|
RABBIT='🐇',
|
||||||
BEAVER='🦫',
|
TIGER='🐅',
|
||||||
TEDDY_BEAR='🧸',
|
TEDDY_BEAR='🧸',
|
||||||
)
|
)
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from .player import Player
|
from .player import Player
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from random import choice
|
from random import choice
|
||||||
|
|
||||||
from .player import Player
|
from .player import Player
|
||||||
@ -52,13 +55,13 @@ class Monster(FightingEntity):
|
|||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
class Beaver(Monster):
|
class Tiger(Monster):
|
||||||
"""
|
"""
|
||||||
A beaver monster
|
A tiger monster
|
||||||
"""
|
"""
|
||||||
def __init__(self, strength: int = 2, maxhealth: int = 20,
|
def __init__(self, strength: int = 2, maxhealth: int = 20,
|
||||||
*args, **kwargs) -> None:
|
*args, **kwargs) -> None:
|
||||||
super().__init__(name="beaver", strength=strength,
|
super().__init__(name="tiger", strength=strength,
|
||||||
maxhealth=maxhealth, *args, **kwargs)
|
maxhealth=maxhealth, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import Dict, Tuple
|
from typing import Dict, Tuple
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
from json import JSONDecodeError
|
||||||
from random import randint
|
from random import randint
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
import json
|
import json
|
||||||
@ -34,6 +37,7 @@ class Game:
|
|||||||
self.settings.write_settings()
|
self.settings.write_settings()
|
||||||
self.settings_menu.update_values(self.settings)
|
self.settings_menu.update_values(self.settings)
|
||||||
self.logs = Logs()
|
self.logs = Logs()
|
||||||
|
self.message = None
|
||||||
|
|
||||||
def new_game(self) -> None:
|
def new_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
@ -55,7 +59,7 @@ class Game:
|
|||||||
when the given key gets pressed.
|
when the given key gets pressed.
|
||||||
"""
|
"""
|
||||||
while True: # pragma no cover
|
while True: # pragma no cover
|
||||||
screen.clear()
|
screen.erase()
|
||||||
screen.refresh()
|
screen.refresh()
|
||||||
self.display_actions(DisplayActions.REFRESH)
|
self.display_actions(DisplayActions.REFRESH)
|
||||||
key = screen.getkey()
|
key = screen.getkey()
|
||||||
@ -68,6 +72,11 @@ class Game:
|
|||||||
Indicates what should be done when the given key is pressed,
|
Indicates what should be done when the given key is pressed,
|
||||||
according to the current game state.
|
according to the current game state.
|
||||||
"""
|
"""
|
||||||
|
if self.message:
|
||||||
|
self.message = None
|
||||||
|
self.display_actions(DisplayActions.REFRESH)
|
||||||
|
return
|
||||||
|
|
||||||
if self.state == GameMode.PLAY:
|
if self.state == GameMode.PLAY:
|
||||||
self.handle_key_pressed_play(key)
|
self.handle_key_pressed_play(key)
|
||||||
elif self.state == GameMode.MAINMENU:
|
elif self.state == GameMode.MAINMENU:
|
||||||
@ -130,9 +139,24 @@ class Game:
|
|||||||
"""
|
"""
|
||||||
Loads the game from a dictionary
|
Loads the game from a dictionary
|
||||||
"""
|
"""
|
||||||
self.map.load_state(d)
|
try:
|
||||||
# noinspection PyTypeChecker
|
self.map.load_state(d)
|
||||||
self.player = self.map.find_entities(Player)[0]
|
except KeyError:
|
||||||
|
self.message = "Some keys are missing in your save file.\n" \
|
||||||
|
"Your save seems to be corrupt. It got deleted."
|
||||||
|
os.unlink(ResourceManager.get_config_path("save.json"))
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
return
|
||||||
|
|
||||||
|
players = self.map.find_entities(Player)
|
||||||
|
if not players:
|
||||||
|
self.message = "No player was found on this map!\n" \
|
||||||
|
"Maybe you died?"
|
||||||
|
self.player.health = 0
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.player = players[0]
|
||||||
self.display_actions(DisplayActions.UPDATE)
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
|
||||||
def load_game(self) -> None:
|
def load_game(self) -> None:
|
||||||
@ -142,7 +166,14 @@ class Game:
|
|||||||
file_path = ResourceManager.get_config_path("save.json")
|
file_path = ResourceManager.get_config_path("save.json")
|
||||||
if os.path.isfile(file_path):
|
if os.path.isfile(file_path):
|
||||||
with open(file_path, "r") as f:
|
with open(file_path, "r") as f:
|
||||||
self.load_state(json.loads(f.read()))
|
try:
|
||||||
|
state = json.loads(f.read())
|
||||||
|
self.load_state(state)
|
||||||
|
except JSONDecodeError:
|
||||||
|
self.message = "The JSON file is not correct.\n" \
|
||||||
|
"Your save seems corrupted. It got deleted."
|
||||||
|
os.unlink(file_path)
|
||||||
|
self.display_actions(DisplayActions.UPDATE)
|
||||||
|
|
||||||
def save_game(self) -> None:
|
def save_game(self) -> None:
|
||||||
"""
|
"""
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from math import sqrt
|
from math import sqrt
|
||||||
from random import choice, randint
|
from random import choice, randint
|
||||||
@ -318,9 +320,9 @@ class Entity:
|
|||||||
Returns all entities subclasses
|
Returns all entities subclasses
|
||||||
"""
|
"""
|
||||||
from squirrelbattle.entities.items import Heart, Bomb
|
from squirrelbattle.entities.items import Heart, Bomb
|
||||||
from squirrelbattle.entities.monsters import Beaver, Hedgehog, \
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, \
|
||||||
Rabbit, TeddyBear
|
Rabbit, TeddyBear
|
||||||
return [Beaver, Bomb, Heart, Hedgehog, Rabbit, TeddyBear]
|
return [Tiger, Bomb, Heart, Hedgehog, Rabbit, TeddyBear]
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_all_entity_classes_in_a_dict() -> dict:
|
def get_all_entity_classes_in_a_dict() -> dict:
|
||||||
@ -328,11 +330,11 @@ class Entity:
|
|||||||
Returns all entities subclasses in a dictionary
|
Returns all entities subclasses in a dictionary
|
||||||
"""
|
"""
|
||||||
from squirrelbattle.entities.player import Player
|
from squirrelbattle.entities.player import Player
|
||||||
from squirrelbattle.entities.monsters import Beaver, Hedgehog, Rabbit, \
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \
|
||||||
TeddyBear
|
TeddyBear
|
||||||
from squirrelbattle.entities.items import Bomb, Heart
|
from squirrelbattle.entities.items import Bomb, Heart
|
||||||
return {
|
return {
|
||||||
"Beaver": Beaver,
|
"Tiger": Tiger,
|
||||||
"Bomb": Bomb,
|
"Bomb": Bomb,
|
||||||
"Heart": Heart,
|
"Heart": Heart,
|
||||||
"Hedgehog": Hedgehog,
|
"Hedgehog": Hedgehog,
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
from typing import Any, Generator
|
from typing import Any, Generator
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import curses
|
import curses
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
|
|
||||||
|
@ -0,0 +1,2 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from squirrelbattle.entities.items import Bomb, Heart, Item
|
from squirrelbattle.entities.items import Bomb, Heart, Item
|
||||||
from squirrelbattle.entities.monsters import Beaver, Hedgehog, Rabbit, TeddyBear
|
from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, TeddyBear
|
||||||
from squirrelbattle.entities.player import Player
|
from squirrelbattle.entities.player import Player
|
||||||
from squirrelbattle.interfaces import Entity, Map
|
from squirrelbattle.interfaces import Entity, Map
|
||||||
from squirrelbattle.resources import ResourceManager
|
from squirrelbattle.resources import ResourceManager
|
||||||
@ -36,17 +39,17 @@ class TestEntities(unittest.TestCase):
|
|||||||
"""
|
"""
|
||||||
Test some random stuff with fighting entities.
|
Test some random stuff with fighting entities.
|
||||||
"""
|
"""
|
||||||
entity = Beaver()
|
entity = Tiger()
|
||||||
self.map.add_entity(entity)
|
self.map.add_entity(entity)
|
||||||
self.assertEqual(entity.maxhealth, 20)
|
self.assertEqual(entity.maxhealth, 20)
|
||||||
self.assertEqual(entity.maxhealth, entity.health)
|
self.assertEqual(entity.maxhealth, entity.health)
|
||||||
self.assertEqual(entity.strength, 2)
|
self.assertEqual(entity.strength, 2)
|
||||||
for _ in range(9):
|
for _ in range(9):
|
||||||
self.assertEqual(entity.hit(entity),
|
self.assertEqual(entity.hit(entity),
|
||||||
"beaver hits beaver. beaver takes 2 damage.")
|
"tiger hits tiger. tiger takes 2 damage.")
|
||||||
self.assertFalse(entity.dead)
|
self.assertFalse(entity.dead)
|
||||||
self.assertEqual(entity.hit(entity), "beaver hits beaver. "
|
self.assertEqual(entity.hit(entity), "tiger hits tiger. "
|
||||||
+ "beaver takes 2 damage. beaver dies.")
|
+ "tiger takes 2 damage. tiger dies.")
|
||||||
self.assertTrue(entity.dead)
|
self.assertTrue(entity.dead)
|
||||||
|
|
||||||
entity = Rabbit()
|
entity = Rabbit()
|
||||||
|
@ -1,6 +1,13 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
|
from squirrelbattle.resources import ResourceManager
|
||||||
|
|
||||||
|
from squirrelbattle.enums import DisplayActions
|
||||||
|
|
||||||
from squirrelbattle.bootstrap import Bootstrap
|
from squirrelbattle.bootstrap import Bootstrap
|
||||||
from squirrelbattle.display.display import Display
|
from squirrelbattle.display.display import Display
|
||||||
from squirrelbattle.display.display_manager import DisplayManager
|
from squirrelbattle.display.display_manager import DisplayManager
|
||||||
@ -38,6 +45,27 @@ class TestGame(unittest.TestCase):
|
|||||||
new_state = self.game.save_state()
|
new_state = self.game.save_state()
|
||||||
self.assertEqual(old_state, new_state)
|
self.assertEqual(old_state, new_state)
|
||||||
|
|
||||||
|
# Error on loading save
|
||||||
|
with open(ResourceManager.get_config_path("save.json"), "w") as f:
|
||||||
|
f.write("I am not a JSON file")
|
||||||
|
self.assertIsNone(self.game.message)
|
||||||
|
self.game.load_game()
|
||||||
|
self.assertIsNotNone(self.game.message)
|
||||||
|
self.game.message = None
|
||||||
|
|
||||||
|
with open(ResourceManager.get_config_path("save.json"), "w") as f:
|
||||||
|
f.write("{}")
|
||||||
|
self.assertIsNone(self.game.message)
|
||||||
|
self.game.load_game()
|
||||||
|
self.assertIsNotNone(self.game.message)
|
||||||
|
self.game.message = None
|
||||||
|
|
||||||
|
# Load game with a dead player
|
||||||
|
self.game.map.remove_entity(self.game.player)
|
||||||
|
self.game.save_game()
|
||||||
|
self.game.load_game()
|
||||||
|
self.assertIsNotNone(self.game.message)
|
||||||
|
|
||||||
def test_bootstrap_fail(self) -> None:
|
def test_bootstrap_fail(self) -> None:
|
||||||
"""
|
"""
|
||||||
Ensure that the test can't play the game,
|
Ensure that the test can't play the game,
|
||||||
@ -289,3 +317,13 @@ class TestGame(unittest.TestCase):
|
|||||||
Check that some functions are not implemented, only for coverage.
|
Check that some functions are not implemented, only for coverage.
|
||||||
"""
|
"""
|
||||||
self.assertRaises(NotImplementedError, Display.display, None)
|
self.assertRaises(NotImplementedError, Display.display, None)
|
||||||
|
|
||||||
|
def test_messages(self) -> None:
|
||||||
|
"""
|
||||||
|
Display error messages.
|
||||||
|
"""
|
||||||
|
self.game.message = "I am an error"
|
||||||
|
self.game.display_actions(DisplayActions.UPDATE)
|
||||||
|
self.game.display_actions(DisplayActions.REFRESH)
|
||||||
|
self.game.handle_key_pressed(None, "random key")
|
||||||
|
self.assertIsNone(self.game.message)
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from squirrelbattle.display.texturepack import TexturePack
|
from squirrelbattle.display.texturepack import TexturePack
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
|
||||||
class FakePad:
|
class FakePad:
|
||||||
"""
|
"""
|
||||||
In order to run tests, we simulate a fake curses pad that accepts functions
|
In order to run tests, we simulate a fake curses pad that accepts functions
|
||||||
@ -10,8 +16,11 @@ class FakePad:
|
|||||||
smincol: int, smaxrow: int, smaxcol: int) -> None:
|
smincol: int, smaxrow: int, smaxcol: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def clear(self) -> None:
|
def erase(self) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def resize(self, height: int, width: int) -> None:
|
def resize(self, height: int, width: int) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def getmaxyx(self) -> Tuple[int, int]:
|
||||||
|
return 42, 42
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
# Copyright (C) 2020 by ÿnérant, eichhornchen, nicomarg, charlse
|
||||||
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from squirrelbattle.settings import Settings
|
from squirrelbattle.settings import Settings
|
||||||
|
Reference in New Issue
Block a user