initial commit
4
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
build/
|
||||||
|
env/
|
||||||
|
__pycache__/
|
||||||
|
*.db
|
||||||
BIN
Logo/PythonGame (1).jpg
Normal file
|
After Width: | Height: | Size: 222 KiB |
BIN
Logo/PythonGame (1).png
Normal file
|
After Width: | Height: | Size: 2.4 MiB |
BIN
Logo/PythonGame-removebg.png
Normal file
|
After Width: | Height: | Size: 3 MiB |
BIN
Logo/PythonGame.jpg
Normal file
|
After Width: | Height: | Size: 449 KiB |
BIN
Logo/logo.ico
Normal file
|
After Width: | Height: | Size: 66 KiB |
61
README.md
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
<div class="title-logo">
|
||||||
|
<h1>Serpent's Legacy <em class="otherName">(Path of the Loner)</em></h1>
|
||||||
|
<img src="https://github.com/ExostFlashPro/path-of-the-loner/blob/main/Logo/PythonGame%20(1).png?raw=true" alt="Serpent's Legacy Logo">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
**Serpent's Legacy** is a game developed in **Python** using **object-oriented programming**. It offers an immersive experience with **PVP** and **PVE** combat, where players embody different heroes and face increasingly difficult enemies.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Three character classes**: Archer, Warrior, Mage
|
||||||
|
- **Equipment system**: Customizable armor and weapons
|
||||||
|
- **PVP mode**: Face other players in strategic duels
|
||||||
|
- **PVE mode**: Progress through the **Hall of the Fallen**, consisting of multiple rooms with increasing monster difficulty
|
||||||
|
|
||||||
|
## Technologies Used
|
||||||
|
|
||||||
|
- **Language**: Python
|
||||||
|
- **Paradigm**: Object-oriented programming
|
||||||
|
- **Frameworks & Libraries**: sty,
|
||||||
|
|
||||||
|
## Project Management
|
||||||
|
|
||||||
|
The project was carried out with a structured approach, divided into several **milestones** to ensure smooth and efficient progress. Task tracking and scheduling helped optimize development and ensure that objectives were met.
|
||||||
|
|
||||||
|
## Future Improvements
|
||||||
|
|
||||||
|
Several areas for improvement have been identified to enhance the game, including:
|
||||||
|
|
||||||
|
- **Graphics**: Improving visuals and UI for better gameplay
|
||||||
|
- **Artificial Intelligence**: Making enemies more dynamic and strategic
|
||||||
|
- **Database**: Optimizing data storage and player management
|
||||||
|
|
||||||
|
## How to Run the Project
|
||||||
|
|
||||||
|
### <span class="method">Method 1:</span> Clone the repository and run the executable
|
||||||
|
|
||||||
|
1. **Clone the repository**:
|
||||||
|
```bash
|
||||||
|
git clone <REPO_URL>
|
||||||
|
cd path-of-the-Loner
|
||||||
|
```
|
||||||
|
2. **Run the game**:
|
||||||
|
- Navigate to the dist folder
|
||||||
|
- Launch the provided executable
|
||||||
|
|
||||||
|
### <span class="method">Method 2:</span> Download the executable directly
|
||||||
|
|
||||||
|
1. Download the available executable from the dist folder
|
||||||
|
2. Run the game directly without any additional installation
|
||||||
|
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
- **ClemcleRagazzo** _(MOULIS Clément)_
|
||||||
|
- **ExostFlash** _(MAIZY Amaury)_
|
||||||
|
|
||||||
|
## Supervisor
|
||||||
|
|
||||||
|
- **Sylent** _(HASSAN Aunim)_
|
||||||
30006
Sujet/POO - Path Of The Loner.pdf
Normal file
BIN
Sujet/Présentation.pptx
Normal file
85
Sujet/README - Real.md
Normal file
|
|
@ -0,0 +1,85 @@
|
||||||
|
<style>
|
||||||
|
.title-logo {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 100px; /* Espacement entre le logo et le texte */
|
||||||
|
}
|
||||||
|
.title-logo img {
|
||||||
|
width: 150px;
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
color: rgb(245, 167, 0);
|
||||||
|
}
|
||||||
|
.otherName {
|
||||||
|
color: rgba(245, 167, 0, 0.4)
|
||||||
|
}
|
||||||
|
h2 {
|
||||||
|
color: rgb(23, 137, 252);
|
||||||
|
}
|
||||||
|
.method {
|
||||||
|
color: rgb(120, 194, 253);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="title-logo">
|
||||||
|
<h1>Serpent's Legacy <em class="otherName">(Path of the Loner)</em></h1>
|
||||||
|
<img src="./Logo/PythonGame (1).png" alt="Serpent's Legacy Logo">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Project Overview
|
||||||
|
|
||||||
|
**Serpent's Legacy** is a game developed in **Python** using **object-oriented programming**. It offers an immersive experience with **PVP** and **PVE** combat, where players embody different heroes and face increasingly difficult enemies.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Three character classes**: Archer, Warrior, Mage
|
||||||
|
- **Equipment system**: Customizable armor and weapons
|
||||||
|
- **PVP mode**: Face other players in strategic duels
|
||||||
|
- **PVE mode**: Progress through the **Hall of the Fallen**, consisting of multiple rooms with increasing monster difficulty
|
||||||
|
|
||||||
|
## Technologies Used
|
||||||
|
|
||||||
|
- **Language**: Python
|
||||||
|
- **Paradigm**: Object-oriented programming
|
||||||
|
- **Frameworks & Libraries**: (To be completed if necessary, e.g., Pygame, Tkinter, etc.)
|
||||||
|
|
||||||
|
## Project Management
|
||||||
|
|
||||||
|
The project was carried out with a structured approach, divided into several **milestones** to ensure smooth and efficient progress. Task tracking and scheduling helped optimize development and ensure that objectives were met.
|
||||||
|
|
||||||
|
## Future Improvements
|
||||||
|
|
||||||
|
Several areas for improvement have been identified to enhance the game, including:
|
||||||
|
|
||||||
|
- **Graphics**: Improving visuals and UI for better gameplay
|
||||||
|
- **Artificial Intelligence**: Making enemies more dynamic and strategic
|
||||||
|
- **Database**: Optimizing data storage and player management
|
||||||
|
|
||||||
|
## How to Run the Project
|
||||||
|
|
||||||
|
### <span class="method">Method 1:</span> Clone the repository and run the executable
|
||||||
|
|
||||||
|
1. **Clone the repository**:
|
||||||
|
```bash
|
||||||
|
git clone <REPO_URL>
|
||||||
|
cd path-of-the-Loner
|
||||||
|
```
|
||||||
|
2. **Run the game**:
|
||||||
|
- Navigate to the dist folder
|
||||||
|
- Launch the provided executable
|
||||||
|
|
||||||
|
### <span class="method">Method 2:</span> Download the executable directly
|
||||||
|
|
||||||
|
1. Download the available executable from the dist folder
|
||||||
|
2. Run the game directly without any additional installation
|
||||||
|
|
||||||
|
|
||||||
|
## Authors
|
||||||
|
|
||||||
|
- **ClemcleRagazzo** _(MOULIS Clément)_
|
||||||
|
- **ExostFlash** _(MAIZY Amaury)_
|
||||||
|
|
||||||
|
## Supervisor
|
||||||
|
|
||||||
|
- **Sylent** _(HASSAN Aunim)_
|
||||||
47
controllers/PveController.py
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
# pveController
|
||||||
|
|
||||||
|
from views.PVP.chooseCharacterUI import ChooseCharacterUI
|
||||||
|
from views.PVE.roomUI import RoomUI
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from controllers.mainController import MainController
|
||||||
|
|
||||||
|
|
||||||
|
class PveController:
|
||||||
|
|
||||||
|
def __init__(self, mController: "MainController") -> None:
|
||||||
|
self.mController = mController
|
||||||
|
self.db = self.mController.db
|
||||||
|
MAX_HEROES = 3
|
||||||
|
|
||||||
|
self.heroes = []
|
||||||
|
choice = -1
|
||||||
|
|
||||||
|
while choice < 1 or choice > MAX_HEROES:
|
||||||
|
print(f"How many heroes do you want in your team ?")
|
||||||
|
print(f"Choose between {fg.blue}1{fg.rs} and {fg.blue}{MAX_HEROES}{fg.rs}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice = int(input("How many heroes do you want: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red} Input a valid number {fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > MAX_HEROES:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again {fg.rs}")
|
||||||
|
|
||||||
|
for i in range(0, choice):
|
||||||
|
self.heroes.append(ChooseCharacterUI(self, False).hero)
|
||||||
|
|
||||||
|
RoomUI(self, 50, self.heroes)
|
||||||
|
RoomUI(self, 100, self.heroes)
|
||||||
|
RoomUI(self, 150, self.heroes)
|
||||||
|
RoomUI(self, 200, self.heroes)
|
||||||
|
|
||||||
|
if self.heroes:
|
||||||
|
print("You passed all rooms")
|
||||||
37
controllers/PvpController.py
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
# pvpController
|
||||||
|
|
||||||
|
# views
|
||||||
|
from views.PVP.chooseCharacterUI import ChooseCharacterUI
|
||||||
|
from views.PVP.arenaUI import ArenaUI
|
||||||
|
|
||||||
|
# models
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
from models.heroes.archery import Archery
|
||||||
|
from models.heroes.warrior import Warrior
|
||||||
|
from models.heroes.wizard import Wizard
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from controllers.mainController import MainController
|
||||||
|
|
||||||
|
|
||||||
|
class PvpController:
|
||||||
|
def __init__(self, mController: "MainController") -> None:
|
||||||
|
self.mController = mController
|
||||||
|
self.db = self.mController.db
|
||||||
|
|
||||||
|
self.hero: Hero | Archery | Warrior | Wizard = ChooseCharacterUI(
|
||||||
|
self, False
|
||||||
|
).hero
|
||||||
|
|
||||||
|
print("---------------")
|
||||||
|
print("Création du personnage")
|
||||||
|
self.opponent: Hero | Archery | Warrior | Wizard = ChooseCharacterUI(
|
||||||
|
self, True
|
||||||
|
).hero
|
||||||
|
|
||||||
|
print("---------------")
|
||||||
|
|
||||||
|
ArenaUI(self)
|
||||||
43
controllers/mainController.py
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
# mainController
|
||||||
|
|
||||||
|
from controllers.PvpController import PvpController
|
||||||
|
from controllers.PveController import PveController
|
||||||
|
|
||||||
|
from database.mainDB import MainDB
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
|
||||||
|
class MainController:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.db = MainDB()
|
||||||
|
|
||||||
|
self.init()
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
PVP_MODE = 1
|
||||||
|
PVE_MODE = 2
|
||||||
|
game_mode = [PVP_MODE, PVE_MODE]
|
||||||
|
|
||||||
|
choice = 0
|
||||||
|
while choice not in game_mode:
|
||||||
|
print("Choose your game mode")
|
||||||
|
print(f"{PVP_MODE}. PVP mode")
|
||||||
|
print(f"{PVE_MODE}. PVE mode")
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice = int(input("Choose your gamemode: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice == PVP_MODE:
|
||||||
|
PvpController(self)
|
||||||
|
elif choice == PVE_MODE:
|
||||||
|
PveController(self)
|
||||||
|
else:
|
||||||
|
raise Exception("An error occured")
|
||||||
|
|
||||||
|
def close_game(self):
|
||||||
|
input("Press any key to quit game")
|
||||||
|
self.db.close_db()
|
||||||
BIN
database/SQLiteSpy.exe
Normal file
51
database/databases/armorDB.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# armorDB
|
||||||
|
|
||||||
|
from models.loots.armor import Armor
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
from models.loots.loot import Loot
|
||||||
|
|
||||||
|
from database.databases.lootDB import LootDB
|
||||||
|
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from database.mainDB import MainDB
|
||||||
|
|
||||||
|
|
||||||
|
class ArmorDB(LootDB):
|
||||||
|
|
||||||
|
def __init__(self, db: "MainDB") -> None:
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
def get_armor(self) -> list[Armor]:
|
||||||
|
query = "SELECT * FROM loots WHERE types_id = ?"
|
||||||
|
values = (5,)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
list_return = []
|
||||||
|
for result in results:
|
||||||
|
list_return.append(self.define_loot(result))
|
||||||
|
|
||||||
|
return list_return
|
||||||
|
|
||||||
|
def define_loot(self, result: list) -> Armor:
|
||||||
|
id = result[0]
|
||||||
|
title = result[1]
|
||||||
|
type = result[2]
|
||||||
|
loot_value = result[3]
|
||||||
|
value = result[4]
|
||||||
|
description = result[5]
|
||||||
|
drop_rate = result[6]
|
||||||
|
|
||||||
|
armor = Armor(title, description, type, loot_value, value, drop_rate)
|
||||||
|
armor.id = id
|
||||||
|
|
||||||
|
return armor
|
||||||
|
|
||||||
|
def get_armor_by_hero_type(self, hero: Hero) -> list[Armor]:
|
||||||
|
return self.get_loots_by_hero_and_loot_type(hero, Loot.ARMOR)
|
||||||
114
database/databases/heroDB.py
Normal file
|
|
@ -0,0 +1,114 @@
|
||||||
|
# heroDB
|
||||||
|
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
from models.heroes.archery import Archery
|
||||||
|
from models.heroes.warrior import Warrior
|
||||||
|
from models.heroes.wizard import Wizard
|
||||||
|
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from database.mainDB import MainDB
|
||||||
|
|
||||||
|
|
||||||
|
class HeroDB:
|
||||||
|
def __init__(self, db: "MainDB") -> None:
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
def get_all_heroes(self) -> list[Hero]:
|
||||||
|
query = "SELECT * FROM heroes WHERE ?"
|
||||||
|
values = (1,)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
heroes = []
|
||||||
|
for result in results:
|
||||||
|
heroes.append(self.define_hero(result))
|
||||||
|
|
||||||
|
return heroes
|
||||||
|
|
||||||
|
def get_archers(self) -> list[Hero]:
|
||||||
|
query = "SELECT * FROM heroes WHERE types_id = ?"
|
||||||
|
values = (Hero.ARCHERY,)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
list_return = []
|
||||||
|
for result in results:
|
||||||
|
list_return.append(self.define_hero(result))
|
||||||
|
|
||||||
|
return list_return
|
||||||
|
|
||||||
|
def get_warriors(self) -> list[Hero]:
|
||||||
|
query = "SELECT * FROM heroes WHERE types_id = ?"
|
||||||
|
values = (Hero.WARRIOR,)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
list_return = []
|
||||||
|
for result in results:
|
||||||
|
list_return.append(self.define_hero(result))
|
||||||
|
|
||||||
|
return list_return
|
||||||
|
|
||||||
|
def get_wizards(self) -> list[Hero]:
|
||||||
|
query = "SELECT * FROM heroes WHERE types_id = ?"
|
||||||
|
values = (Hero.WIZARD,)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
list_return = []
|
||||||
|
for result in results:
|
||||||
|
list_return.append(self.define_hero(result))
|
||||||
|
|
||||||
|
return list_return
|
||||||
|
|
||||||
|
def define_hero(self, result: list) -> Hero:
|
||||||
|
id = result[0]
|
||||||
|
title = result[1]
|
||||||
|
types_id = result[2]
|
||||||
|
health_points = result[3]
|
||||||
|
attack_power = result[4]
|
||||||
|
defense = result[5]
|
||||||
|
mana = result[6]
|
||||||
|
description = result[7]
|
||||||
|
|
||||||
|
if types_id == Hero.ARCHERY:
|
||||||
|
hero = Archery(
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
health_points,
|
||||||
|
attack_power,
|
||||||
|
defense,
|
||||||
|
)
|
||||||
|
elif types_id == Hero.WARRIOR:
|
||||||
|
hero = Warrior(
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
health_points,
|
||||||
|
attack_power,
|
||||||
|
defense,
|
||||||
|
)
|
||||||
|
elif types_id == Hero.WIZARD:
|
||||||
|
hero = Wizard(
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
health_points,
|
||||||
|
attack_power,
|
||||||
|
defense,
|
||||||
|
mana,
|
||||||
|
)
|
||||||
|
|
||||||
|
hero.id = id
|
||||||
|
|
||||||
|
return hero
|
||||||
50
database/databases/lootDB.py
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
# lootDB
|
||||||
|
|
||||||
|
from models.loots.loot import Loot
|
||||||
|
from models.heroes.monster import Monster
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from database.mainDB import MainDB
|
||||||
|
|
||||||
|
|
||||||
|
class LootDB:
|
||||||
|
|
||||||
|
def __init__(self, db: "MainDB") -> None:
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
def get_loots_by_hero_and_loot_type(self, hero: Hero, loot_type: int) -> list:
|
||||||
|
query = """
|
||||||
|
SELECT l.*
|
||||||
|
FROM loots l
|
||||||
|
INNER JOIN characters_has_loots chl ON l.id = chl.loot_type
|
||||||
|
WHERE chl.character_type = ? AND l.types_id = ?;
|
||||||
|
"""
|
||||||
|
values = (hero.type, loot_type)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
loots = []
|
||||||
|
for result in results:
|
||||||
|
loots.append(self.define_loot(result))
|
||||||
|
|
||||||
|
return loots
|
||||||
|
|
||||||
|
def define_loot(self, result: list) -> dict:
|
||||||
|
id = result[0]
|
||||||
|
title = result[1]
|
||||||
|
type = result[2]
|
||||||
|
loot_value = result[3]
|
||||||
|
value = result[4]
|
||||||
|
description = result[5]
|
||||||
|
drop_rate = result[6]
|
||||||
|
|
||||||
|
loot = Loot(title, description, type, loot_value, value, drop_rate)
|
||||||
|
loot.id = id
|
||||||
|
|
||||||
|
return loot
|
||||||
51
database/databases/monsterDB.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# monsterDB
|
||||||
|
|
||||||
|
from models.heroes.monster import Monster
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from database.mainDB import MainDB
|
||||||
|
|
||||||
|
|
||||||
|
class MonsterDB:
|
||||||
|
def __init__(self, db: "MainDB") -> None:
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
def get_all_monsters(self) -> list[Monster]:
|
||||||
|
query = "SELECT * FROM monsters WHERE types_id IN (?, ?, ?, ?, ?)"
|
||||||
|
values = (
|
||||||
|
Monster.BEAST,
|
||||||
|
Monster.HUMANOID,
|
||||||
|
Monster.UNDEAD,
|
||||||
|
Monster.DRAGON,
|
||||||
|
Monster.ELEMENTAL,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
monsters = []
|
||||||
|
for result in results:
|
||||||
|
monsters.append(self.define_monster(result))
|
||||||
|
|
||||||
|
return monsters
|
||||||
|
|
||||||
|
def define_monster(self, result: list) -> Monster:
|
||||||
|
id = result[0]
|
||||||
|
title = result[1]
|
||||||
|
types_id = result[2]
|
||||||
|
health_points = result[3]
|
||||||
|
attack_power = result[4]
|
||||||
|
defense = result[5]
|
||||||
|
description = result[6]
|
||||||
|
|
||||||
|
monster = Monster(
|
||||||
|
title, description, health_points, attack_power, defense, types_id
|
||||||
|
)
|
||||||
|
|
||||||
|
monster.id = id
|
||||||
|
|
||||||
|
return monster
|
||||||
51
database/databases/weaponDB.py
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
# weaponDB
|
||||||
|
|
||||||
|
from models.loots.weapon import Weapon
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
from models.loots.loot import Loot
|
||||||
|
|
||||||
|
from database.databases.lootDB import LootDB
|
||||||
|
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from database.mainDB import MainDB
|
||||||
|
|
||||||
|
|
||||||
|
class WeaponDB(LootDB):
|
||||||
|
|
||||||
|
def __init__(self, db: "MainDB") -> None:
|
||||||
|
self.db = db
|
||||||
|
|
||||||
|
def get_weapons(self) -> list[Weapon]:
|
||||||
|
query = "SELECT * FROM loots WHERE types_id = ?"
|
||||||
|
values = (Weapon.WEAPON,)
|
||||||
|
|
||||||
|
self.db.sql_query(query, values)
|
||||||
|
|
||||||
|
results = self.db.cursor.fetchall()
|
||||||
|
|
||||||
|
list_return = []
|
||||||
|
for result in results:
|
||||||
|
list_return.append(self.define_loot(result))
|
||||||
|
|
||||||
|
return list_return
|
||||||
|
|
||||||
|
def define_loot(self, result: list) -> Weapon:
|
||||||
|
id = result[0]
|
||||||
|
title = result[1]
|
||||||
|
type = result[2]
|
||||||
|
loot_value = result[3]
|
||||||
|
value = result[4]
|
||||||
|
description = result[5]
|
||||||
|
drop_rate = result[6]
|
||||||
|
|
||||||
|
weapon = Weapon(title, description, type, loot_value, value, drop_rate)
|
||||||
|
weapon.id = id
|
||||||
|
|
||||||
|
return weapon
|
||||||
|
|
||||||
|
def get_weapon_by_hero_type(self, hero: Hero) -> list[Weapon]:
|
||||||
|
return self.get_loots_by_hero_and_loot_type(hero, Loot.WEAPON)
|
||||||
561
database/mainDB.py
Normal file
|
|
@ -0,0 +1,561 @@
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from database.databases.armorDB import ArmorDB
|
||||||
|
from database.databases.weaponDB import WeaponDB
|
||||||
|
from database.databases.heroDB import HeroDB
|
||||||
|
from database.databases.monsterDB import MonsterDB
|
||||||
|
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
FOLDER_DB = "data"
|
||||||
|
FILE_DB = "mydb.db"
|
||||||
|
FILE_PATH_DB = os.path.join(os.getcwd(), FOLDER_DB, FILE_DB)
|
||||||
|
|
||||||
|
|
||||||
|
class MainDB:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
self.were_already_existing = True
|
||||||
|
|
||||||
|
if not os.path.exists(FOLDER_DB):
|
||||||
|
os.makedirs(FOLDER_DB)
|
||||||
|
|
||||||
|
if not os.path.exists(FILE_PATH_DB):
|
||||||
|
with open(FILE_PATH_DB, "w") as db_file:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.were_already_existing = False
|
||||||
|
|
||||||
|
# Connexion à la base de données SQLite
|
||||||
|
self.conn = sqlite3.connect(FILE_PATH_DB)
|
||||||
|
self.cursor = self.conn.cursor()
|
||||||
|
|
||||||
|
self.create_tables()
|
||||||
|
|
||||||
|
self.add_databases()
|
||||||
|
|
||||||
|
# print(
|
||||||
|
# f"Database '{FILE_PATH_DB}' and tables with initial data created successfully."
|
||||||
|
# )
|
||||||
|
|
||||||
|
def close_db(self):
|
||||||
|
self.conn.close()
|
||||||
|
|
||||||
|
def add_databases(self):
|
||||||
|
self.weapon_db = WeaponDB(self)
|
||||||
|
self.armor_db = ArmorDB(self)
|
||||||
|
self.hero_db = HeroDB(self)
|
||||||
|
self.monster_db = MonsterDB(self)
|
||||||
|
|
||||||
|
def create_tables(self):
|
||||||
|
# Création des tables
|
||||||
|
self.cursor.executescript(
|
||||||
|
"""
|
||||||
|
CREATE TABLE IF NOT EXISTS types (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS monsters (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT,
|
||||||
|
types_id INTEGER NOT NULL,
|
||||||
|
health_points INTEGER,
|
||||||
|
attack_power REAL,
|
||||||
|
defense REAL,
|
||||||
|
description TEXT,
|
||||||
|
FOREIGN KEY (types_id) REFERENCES types (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS values_of_loots (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT,
|
||||||
|
description TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS loots (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT,
|
||||||
|
types_id INTEGER NOT NULL,
|
||||||
|
values_of_loots_id INTEGER NOT NULL,
|
||||||
|
value INTEGER NOT NULL,
|
||||||
|
description TEXT,
|
||||||
|
drop_rate REAL,
|
||||||
|
FOREIGN KEY (types_id) REFERENCES types (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||||
|
FOREIGN KEY (values_of_loots_id) REFERENCES values_of_loots (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS heroes (
|
||||||
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
title TEXT,
|
||||||
|
types_id INTEGER NOT NULL,
|
||||||
|
health_points INTEGER,
|
||||||
|
attack_power REAL,
|
||||||
|
defense REAL,
|
||||||
|
mana INTEGER,
|
||||||
|
description TEXT,
|
||||||
|
FOREIGN KEY (types_id) REFERENCES types (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS characters_has_loots (
|
||||||
|
character_type INTEGER NOT NULL,
|
||||||
|
loot_type INTEGER NOT NULL,
|
||||||
|
PRIMARY KEY (character_type, loot_type),
|
||||||
|
FOREIGN KEY (character_type) REFERENCES heroes (id) ON DELETE NO ACTION ON UPDATE NO ACTION,
|
||||||
|
FOREIGN KEY (loot_type) REFERENCES loots (id) ON DELETE NO ACTION ON UPDATE NO ACTION
|
||||||
|
);
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
if not self.were_already_existing:
|
||||||
|
self.add_tables()
|
||||||
|
|
||||||
|
# print(f"Database and tables with expanded data created successfully.")
|
||||||
|
|
||||||
|
self.conn.commit()
|
||||||
|
|
||||||
|
def add_tables(self):
|
||||||
|
|
||||||
|
# Insertion des données dans la table types
|
||||||
|
self.cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO types (title) VALUES (?);
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
("archer",),
|
||||||
|
("warrior",),
|
||||||
|
("mage",),
|
||||||
|
("weapons",),
|
||||||
|
("armor",),
|
||||||
|
("consumable",),
|
||||||
|
("beast",),
|
||||||
|
("humanoid",),
|
||||||
|
("undead",),
|
||||||
|
("dragon",),
|
||||||
|
("elemental",),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Insertion des données dans la table values_of_loots
|
||||||
|
self.cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO values_of_loots (title, description) VALUES (?, ?);
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
("attack", "The ability to deal damage to an opponent."),
|
||||||
|
("defence", "The ability to reduce or block incoming damage."),
|
||||||
|
("Healing", "The ability to restore lost health."),
|
||||||
|
("Mana Boost", "Restores or increases mana."),
|
||||||
|
("Critical Hit", "Increases chance of dealing critical damage."),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Insertion des données dans la table loots
|
||||||
|
self.cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO loots (title, types_id, values_of_loots_id, value, description, drop_rate)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?);
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"Rusty Sword",
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
14,
|
||||||
|
"A worn-out sword, barely sharp enough to be effective.",
|
||||||
|
40,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Enchanted Bow",
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
5,
|
||||||
|
"A magical bow with increased accuracy and damage.",
|
||||||
|
25,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Mystic Robe",
|
||||||
|
5,
|
||||||
|
2,
|
||||||
|
8,
|
||||||
|
"A robe that enhances the wearer's defense against magic.",
|
||||||
|
30,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Health Potion",
|
||||||
|
6,
|
||||||
|
3,
|
||||||
|
0,
|
||||||
|
"A potion that restores 50 health points.",
|
||||||
|
60,
|
||||||
|
), # Ajout de `0` pour value
|
||||||
|
(
|
||||||
|
"Iron Shield",
|
||||||
|
5,
|
||||||
|
2,
|
||||||
|
7,
|
||||||
|
"A sturdy shield made of iron, providing excellent defense.",
|
||||||
|
40,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Fireball Scroll",
|
||||||
|
6,
|
||||||
|
1,
|
||||||
|
14,
|
||||||
|
"A scroll that teaches the fireball spell to a mage.",
|
||||||
|
20,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Dragon Scale Armor",
|
||||||
|
5,
|
||||||
|
2,
|
||||||
|
20,
|
||||||
|
"Armor crafted from dragon scales, highly durable.",
|
||||||
|
15,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Thunder Sword",
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
8,
|
||||||
|
"A sword infused with thunder magic.",
|
||||||
|
20,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Arcane Scepter",
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
9,
|
||||||
|
"A powerful scepter that amplifies magic.",
|
||||||
|
15,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Potion of damaging Power",
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
3,
|
||||||
|
"Temporarily increases spell power.",
|
||||||
|
30,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Potion of Devastation",
|
||||||
|
4,
|
||||||
|
1,
|
||||||
|
7,
|
||||||
|
"Boosts magical damage for a short time.",
|
||||||
|
25,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Insertion des données dans la table heroes
|
||||||
|
self.cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO heroes (title, types_id, health_points, attack_power, defense, mana, description)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?);
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"Eldon the Brave",
|
||||||
|
2,
|
||||||
|
150,
|
||||||
|
25.0,
|
||||||
|
20.0,
|
||||||
|
10,
|
||||||
|
"A seasoned warrior known for his resilience and strength.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Lyra the Swift",
|
||||||
|
1,
|
||||||
|
100,
|
||||||
|
30.0,
|
||||||
|
15.0,
|
||||||
|
50,
|
||||||
|
"An archer with unmatched speed and precision.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Morgana the Wise",
|
||||||
|
3,
|
||||||
|
80,
|
||||||
|
20.0,
|
||||||
|
10.0,
|
||||||
|
100,
|
||||||
|
"A mage with a deep knowledge of arcane spells.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Tharok the Shieldbearer",
|
||||||
|
2,
|
||||||
|
200,
|
||||||
|
15.0,
|
||||||
|
35.0,
|
||||||
|
5,
|
||||||
|
"A warrior who specializes in defensive tactics.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Selene the Healer",
|
||||||
|
3,
|
||||||
|
90,
|
||||||
|
10.0,
|
||||||
|
10.0,
|
||||||
|
120,
|
||||||
|
"A mage dedicated to supporting her allies with healing magic.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Ragnar the Fierce",
|
||||||
|
2,
|
||||||
|
170,
|
||||||
|
35.0,
|
||||||
|
25.0,
|
||||||
|
15,
|
||||||
|
"A barbarian warrior with immense strength and ferocity.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Elara the Mystic",
|
||||||
|
3,
|
||||||
|
85,
|
||||||
|
25.0,
|
||||||
|
15.0,
|
||||||
|
110,
|
||||||
|
"A mage who commands the elements with finesse.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Galdor the Archer",
|
||||||
|
1,
|
||||||
|
120,
|
||||||
|
40.0,
|
||||||
|
20.0,
|
||||||
|
30,
|
||||||
|
"A master archer with keen eyesight and precision.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Fenrir the Wild",
|
||||||
|
2,
|
||||||
|
160,
|
||||||
|
28.0,
|
||||||
|
18.0,
|
||||||
|
20,
|
||||||
|
"A warrior with a primal fighting style.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Aurora the Lightbringer",
|
||||||
|
3,
|
||||||
|
95,
|
||||||
|
18.0,
|
||||||
|
12.0,
|
||||||
|
130,
|
||||||
|
"A mage who wields the power of light.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Insertion des données dans la table monsters
|
||||||
|
self.cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO monsters (title, types_id, health_points, attack_power, defense, description)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?);
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
(
|
||||||
|
"Goblin Grunt",
|
||||||
|
7,
|
||||||
|
50,
|
||||||
|
10.0,
|
||||||
|
5.0,
|
||||||
|
"A small but vicious creature, often found in caves.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Forest Troll",
|
||||||
|
7,
|
||||||
|
200,
|
||||||
|
30.0,
|
||||||
|
25.0,
|
||||||
|
"A massive troll that roams the dense forests.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Dark Sorcerer",
|
||||||
|
8,
|
||||||
|
150,
|
||||||
|
40.0,
|
||||||
|
10.0,
|
||||||
|
"A rogue magician who practices forbidden dark magic.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Shadow Wolf",
|
||||||
|
7,
|
||||||
|
100,
|
||||||
|
20.0,
|
||||||
|
10.0,
|
||||||
|
"A wolf with fur as dark as the night, moving silently.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Skeleton Warrior",
|
||||||
|
9,
|
||||||
|
80,
|
||||||
|
15.0,
|
||||||
|
10.0,
|
||||||
|
"An animated skeleton armed with rusted weapons.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Fire Drake",
|
||||||
|
10,
|
||||||
|
250,
|
||||||
|
50.0,
|
||||||
|
30.0,
|
||||||
|
"A small dragon with the ability to breathe fire.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Ice Elemental",
|
||||||
|
11,
|
||||||
|
180,
|
||||||
|
35.0,
|
||||||
|
20.0,
|
||||||
|
"A being composed of ice, freezing everything it touches.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Bandit Leader",
|
||||||
|
8,
|
||||||
|
120,
|
||||||
|
25.0,
|
||||||
|
15.0,
|
||||||
|
"The cunning leader of a group of bandits.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Cave Spider",
|
||||||
|
7,
|
||||||
|
60,
|
||||||
|
15.0,
|
||||||
|
5.0,
|
||||||
|
"A giant spider that dwells in dark caves.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Wraith",
|
||||||
|
9,
|
||||||
|
110,
|
||||||
|
20.0,
|
||||||
|
10.0,
|
||||||
|
"A ghostly figure that haunts abandoned places.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Lava Golem",
|
||||||
|
10,
|
||||||
|
300,
|
||||||
|
60.0,
|
||||||
|
40.0,
|
||||||
|
"A hulking creature made of molten rock.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Thunderbird",
|
||||||
|
10,
|
||||||
|
220,
|
||||||
|
45.0,
|
||||||
|
25.0,
|
||||||
|
"A mythical bird that controls storms.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Necromancer",
|
||||||
|
8,
|
||||||
|
160,
|
||||||
|
50.0,
|
||||||
|
20.0,
|
||||||
|
"A dark mage who raises the dead to do their bidding.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Dire Bear",
|
||||||
|
7,
|
||||||
|
240,
|
||||||
|
35.0,
|
||||||
|
25.0,
|
||||||
|
"A massive bear with unparalleled strength.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Sea Serpent",
|
||||||
|
10,
|
||||||
|
280,
|
||||||
|
55.0,
|
||||||
|
30.0,
|
||||||
|
"A serpentine monster that lurks in deep waters.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Harpy",
|
||||||
|
8,
|
||||||
|
100,
|
||||||
|
20.0,
|
||||||
|
15.0,
|
||||||
|
"A winged monster with sharp claws and a screeching cry.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Stone Guardian",
|
||||||
|
11,
|
||||||
|
320,
|
||||||
|
40.0,
|
||||||
|
50.0,
|
||||||
|
"A statue brought to life to guard ancient ruins.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Venomous Scorpion",
|
||||||
|
7,
|
||||||
|
90,
|
||||||
|
25.0,
|
||||||
|
10.0,
|
||||||
|
"A giant scorpion with a deadly stinger.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Zombie Horde",
|
||||||
|
9,
|
||||||
|
150,
|
||||||
|
10.0,
|
||||||
|
5.0,
|
||||||
|
"A group of mindless zombies seeking flesh.",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Phoenix",
|
||||||
|
10,
|
||||||
|
200,
|
||||||
|
40.0,
|
||||||
|
20.0,
|
||||||
|
"A mythical bird that rises from its ashes.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Insertion des données dans la table monsters_has_loots
|
||||||
|
self.cursor.executemany(
|
||||||
|
"""
|
||||||
|
INSERT INTO characters_has_loots (character_type, loot_type)
|
||||||
|
VALUES (?, ?);
|
||||||
|
""",
|
||||||
|
[
|
||||||
|
(Hero.WARRIOR, 1),
|
||||||
|
(Hero.WARRIOR, 5),
|
||||||
|
(Hero.WARRIOR, 8),
|
||||||
|
(Hero.ARCHERY, 2),
|
||||||
|
(Hero.ARCHERY, 5),
|
||||||
|
(Hero.WIZARD, 9),
|
||||||
|
(Hero.WIZARD, 10),
|
||||||
|
(Hero.WIZARD, 11),
|
||||||
|
(Hero.WIZARD, 3),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def sql_query(self, query: str, values: tuple, is_selecting=False):
|
||||||
|
try:
|
||||||
|
self.cursor.execute(query, values)
|
||||||
|
if not is_selecting:
|
||||||
|
self.conn.commit()
|
||||||
|
return True
|
||||||
|
except sqlite3.IntegrityError as ie:
|
||||||
|
print(f"Insert DB error {ie}")
|
||||||
|
except sqlite3.OperationalError as oe:
|
||||||
|
print(f"Operational error: {oe}")
|
||||||
|
print("Parameters type:", [type(v) for v in values])
|
||||||
|
print("Parameters value:", values)
|
||||||
|
except sqlite3.DatabaseError as e:
|
||||||
|
print("DB error:", e)
|
||||||
|
except sqlite3.InterfaceError as ie:
|
||||||
|
print(f"Type Error: {ie}")
|
||||||
|
print("Parameters type:", [type(v) for v in values])
|
||||||
|
print("Parameters value:", values)
|
||||||
|
except Exception as e:
|
||||||
|
print("An SQL error occured:", e)
|
||||||
|
return False
|
||||||
BIN
database/mdl/V1.mwb
Normal file
BIN
database/mdl/V1.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
database/mdl/V2.mwb
Normal file
BIN
database/mdl/V2.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
database/mdl/V3.mwb
Normal file
BIN
database/mdl/V3.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
dist/Serpent s Legacy.exe
vendored
Normal file
19
main.py
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# main
|
||||||
|
|
||||||
|
from controllers.mainController import MainController
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
MainController()
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
except TypeError as te:
|
||||||
|
print("Type Error:", te)
|
||||||
|
except IOError as ie:
|
||||||
|
print("IO Error", ie)
|
||||||
|
except Exception as e:
|
||||||
|
print("Error:", e)
|
||||||
39
main.spec
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
# -*- mode: python ; coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
a = Analysis(
|
||||||
|
['main.py'],
|
||||||
|
pathex=[],
|
||||||
|
binaries=[],
|
||||||
|
datas=[],
|
||||||
|
hiddenimports=[],
|
||||||
|
hookspath=[],
|
||||||
|
hooksconfig={},
|
||||||
|
runtime_hooks=[],
|
||||||
|
excludes=[],
|
||||||
|
noarchive=False,
|
||||||
|
optimize=0,
|
||||||
|
)
|
||||||
|
pyz = PYZ(a.pure)
|
||||||
|
|
||||||
|
exe = EXE(
|
||||||
|
pyz,
|
||||||
|
a.scripts,
|
||||||
|
a.binaries,
|
||||||
|
a.datas,
|
||||||
|
[],
|
||||||
|
name='Serpent s Legacy',
|
||||||
|
debug=False,
|
||||||
|
bootloader_ignore_signals=False,
|
||||||
|
strip=False,
|
||||||
|
upx=True,
|
||||||
|
upx_exclude=[],
|
||||||
|
runtime_tmpdir=None,
|
||||||
|
console=True,
|
||||||
|
disable_windowed_traceback=False,
|
||||||
|
argv_emulation=False,
|
||||||
|
target_arch=None,
|
||||||
|
codesign_identity=None,
|
||||||
|
entitlements_file=None,
|
||||||
|
icon='logo\logo.ico'
|
||||||
|
)
|
||||||
25
models/heroes/archery.py
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
# archery
|
||||||
|
|
||||||
|
from models.loots.armor import Armor
|
||||||
|
from models.loots.weapon import Weapon
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
|
||||||
|
class Archery(Hero):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
HP: int,
|
||||||
|
attack_power: int,
|
||||||
|
defense: int,
|
||||||
|
armor: Armor = None,
|
||||||
|
weapon: Weapon = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
name, description, HP, attack_power, defense, Hero.ARCHERY, armor, weapon
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_type_str(self) -> str:
|
||||||
|
return "Archery"
|
||||||
14
models/heroes/character.py
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# characterfg.da_magenta +
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
|
||||||
|
class Character:
|
||||||
|
HERO = 1
|
||||||
|
MONSTER = 2
|
||||||
|
|
||||||
|
def __init__(self, name: str, description: str, HP: int) -> None:
|
||||||
|
self.id: int = None
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.HP = HP
|
||||||
79
models/heroes/hero.py
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
# hero
|
||||||
|
|
||||||
|
from models.heroes.character import Character
|
||||||
|
from models.loots.armor import Armor
|
||||||
|
from models.loots.weapon import Weapon
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
|
||||||
|
class Hero(Character):
|
||||||
|
ARCHERY = 1
|
||||||
|
WARRIOR = 2
|
||||||
|
WIZARD = 3
|
||||||
|
BEAST = 7
|
||||||
|
HUMANOID = 8
|
||||||
|
UNDEAD = 9
|
||||||
|
DRAGON = 10
|
||||||
|
ELEMENTAL = 11
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
HP: int,
|
||||||
|
attack_power: int,
|
||||||
|
defense: int,
|
||||||
|
type: str,
|
||||||
|
armor: Armor = None,
|
||||||
|
weapon: Weapon = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(name, description, HP)
|
||||||
|
self.attack_power = attack_power
|
||||||
|
self.defense = defense
|
||||||
|
self.type = type
|
||||||
|
self.armor = armor
|
||||||
|
self.weapon = weapon
|
||||||
|
|
||||||
|
self.attacks_choice: list = ["Attacks", "Cure"]
|
||||||
|
|
||||||
|
def get_type_str(self) -> str:
|
||||||
|
return "Heroes"
|
||||||
|
|
||||||
|
def attacks(self, opponent: "Hero") -> float:
|
||||||
|
power = None
|
||||||
|
if self.weapon:
|
||||||
|
print(f"{self.name} {fg.red}attacks{fg.rs} with {self.weapon.name}")
|
||||||
|
power = self.weapon.power
|
||||||
|
else:
|
||||||
|
print(
|
||||||
|
f"{self.name} {fg.red}attacks{fg.rs} with {fg.yellow}bare hands{fg.rs}"
|
||||||
|
)
|
||||||
|
power = self.attack_power
|
||||||
|
|
||||||
|
if opponent.armor:
|
||||||
|
power -= opponent.defends()
|
||||||
|
|
||||||
|
return power
|
||||||
|
|
||||||
|
def defends(self) -> float:
|
||||||
|
if self.armor:
|
||||||
|
print(
|
||||||
|
f"{self.armor.name} {fg.blue}delete{fg.rs} {self.armor.defense} damage points"
|
||||||
|
)
|
||||||
|
return self.armor.defense
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def cure(self, hero: "Hero" = None):
|
||||||
|
target = hero if hero else self
|
||||||
|
|
||||||
|
UP_HP = 10
|
||||||
|
print(
|
||||||
|
f"{target.name}: {target.HP} {fg.green}HP{fg.rs} +{UP_HP}{fg.green}HP{fg.rs}"
|
||||||
|
)
|
||||||
|
target.HP += UP_HP
|
||||||
|
|
||||||
|
print(f"{target.name}: {target.HP} {fg.green}HP{fg.rs}")
|
||||||
|
|
||||||
|
return UP_HP
|
||||||
18
models/heroes/monster.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
# monster
|
||||||
|
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
|
||||||
|
class Monster(Hero):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
HP: int,
|
||||||
|
attack_power: int,
|
||||||
|
defense: int,
|
||||||
|
type: str,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(name, description, HP, attack_power, defense, type, None, None)
|
||||||
32
models/heroes/warrior.py
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# warrior
|
||||||
|
|
||||||
|
from models.loots.armor import Armor
|
||||||
|
from models.loots.weapon import Weapon
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
|
||||||
|
class Warrior(Hero):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
HP: int,
|
||||||
|
attack_power: int,
|
||||||
|
defense: int,
|
||||||
|
armor: Armor = None,
|
||||||
|
weapon: Weapon = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
name, description, HP, attack_power, defense, Hero.WARRIOR, armor, weapon
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_type_str(self) -> str:
|
||||||
|
return "Warrior"
|
||||||
|
|
||||||
|
def attacks(self, opponent: "Hero") -> float:
|
||||||
|
damage = 0
|
||||||
|
for i in range(0, 2):
|
||||||
|
damage += super().attacks(opponent)
|
||||||
|
|
||||||
|
return damage
|
||||||
27
models/heroes/wizard.py
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# wizard
|
||||||
|
|
||||||
|
from models.loots.armor import Armor
|
||||||
|
from models.loots.weapon import Weapon
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
|
||||||
|
class Wizard(Hero):
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
HP: int,
|
||||||
|
attack_power: int,
|
||||||
|
defense: int,
|
||||||
|
mana_stock: int,
|
||||||
|
armor: Armor = None,
|
||||||
|
weapon: Weapon = None,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(
|
||||||
|
name, description, HP, attack_power, defense, Hero.WIZARD, armor, weapon
|
||||||
|
)
|
||||||
|
self.mana_stock = mana_stock
|
||||||
|
|
||||||
|
def get_type_str(self) -> str:
|
||||||
|
return "Wizard"
|
||||||
20
models/loots/armor.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# armor
|
||||||
|
|
||||||
|
from models.loots.loot import Loot
|
||||||
|
|
||||||
|
|
||||||
|
class Armor(Loot):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
type: int,
|
||||||
|
loot_value: int,
|
||||||
|
defense: int,
|
||||||
|
drop_rate: int,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(name, description, type, loot_value, defense, drop_rate)
|
||||||
|
self.id = None
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.defense = defense
|
||||||
24
models/loots/loot.py
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# loot
|
||||||
|
|
||||||
|
|
||||||
|
class Loot:
|
||||||
|
WEAPON = 4
|
||||||
|
ARMOR = 5
|
||||||
|
CONSUMABLE = 6
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
title: str,
|
||||||
|
description: str,
|
||||||
|
type: int,
|
||||||
|
loot_value: int,
|
||||||
|
value: int,
|
||||||
|
drop_rate: int,
|
||||||
|
) -> None:
|
||||||
|
self.id: int = None
|
||||||
|
self.title = title
|
||||||
|
self.description = description
|
||||||
|
self.type = type
|
||||||
|
self.loot_value = loot_value
|
||||||
|
self.value = value
|
||||||
|
self.drop_rate = drop_rate
|
||||||
20
models/loots/weapon.py
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# weapon
|
||||||
|
|
||||||
|
from models.loots.loot import Loot
|
||||||
|
|
||||||
|
|
||||||
|
class Weapon(Loot):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
description: str,
|
||||||
|
type: int,
|
||||||
|
loot_value: int,
|
||||||
|
power: int,
|
||||||
|
drop_rate: int,
|
||||||
|
) -> None:
|
||||||
|
super().__init__(name, description, type, loot_value, power, drop_rate)
|
||||||
|
self.id = None
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.power = power
|
||||||
BIN
requirements.txt
Normal file
61
views/PVE/chooseMonstersUI.py
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
# chooseMonstersUI
|
||||||
|
|
||||||
|
from models.heroes.monster import Monster
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from controllers.PveController import PveController
|
||||||
|
|
||||||
|
|
||||||
|
class ChooseMonstersUI:
|
||||||
|
def __init__(
|
||||||
|
self, pveController: "PveController", difficulty: int, is_AI: bool
|
||||||
|
) -> None:
|
||||||
|
MAX_NUMBER_MONSTER = 3
|
||||||
|
self.pveController = pveController
|
||||||
|
self.is_AI = is_AI
|
||||||
|
self.difficulty = difficulty
|
||||||
|
|
||||||
|
self.monster: Monster = None
|
||||||
|
self.monsters: list[Monster] = []
|
||||||
|
|
||||||
|
for i in range(0, MAX_NUMBER_MONSTER):
|
||||||
|
self.set_monster()
|
||||||
|
|
||||||
|
self.monsters.append(self.monster)
|
||||||
|
|
||||||
|
def set_monster(self):
|
||||||
|
monsters = self.pveController.db.monster_db.get_all_monsters()
|
||||||
|
len_monsters = len(monsters)
|
||||||
|
|
||||||
|
choice = -1 # Initialiser à une valeur qui n'est pas un index valide
|
||||||
|
while choice < 1 or choice > len_monsters:
|
||||||
|
for i in range(0, len_monsters):
|
||||||
|
monster = monsters[i]
|
||||||
|
if not self.is_AI:
|
||||||
|
print(f"{i+1}. {monster.get_type_str()} - {monster.name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.is_AI:
|
||||||
|
choice = randint(1, len_monsters)
|
||||||
|
# else:
|
||||||
|
# choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > len_monsters:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again{fg.rs}")
|
||||||
|
|
||||||
|
# L'indice dans la liste est `choice - 1`
|
||||||
|
# car choice commence à partir de 1
|
||||||
|
self.monster = monsters[choice - 1]
|
||||||
|
self.monster.name = fg.da_blue + self.monster.name + fg.rs
|
||||||
|
|
||||||
|
if self.monster.HP > self.difficulty:
|
||||||
|
choice = -1
|
||||||
158
views/PVE/roomUI.py
Normal file
|
|
@ -0,0 +1,158 @@
|
||||||
|
# roomUI
|
||||||
|
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
from models.heroes.monster import Monster
|
||||||
|
from views.PVE.chooseMonstersUI import ChooseMonstersUI
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from controllers.PveController import PveController
|
||||||
|
|
||||||
|
|
||||||
|
class RoomUI:
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
pveController: "PveController",
|
||||||
|
difficulty: int,
|
||||||
|
heroes: list[Hero],
|
||||||
|
) -> None:
|
||||||
|
self.pveController = pveController
|
||||||
|
self.difficulty = difficulty
|
||||||
|
self.heroes = heroes
|
||||||
|
self.monsters: list[Monster] = None
|
||||||
|
|
||||||
|
if self.heroes:
|
||||||
|
print("Monsters creation")
|
||||||
|
for i in range(0, 3):
|
||||||
|
self.monsters = ChooseMonstersUI(
|
||||||
|
pveController, difficulty, True
|
||||||
|
).monsters
|
||||||
|
print(f"{self.monsters[i].name} join the room")
|
||||||
|
|
||||||
|
monster_name = [monster.name for monster in self.monsters]
|
||||||
|
print(f"Here your new ennemis: {(", ".join(monster_name)).strip()}")
|
||||||
|
|
||||||
|
while self.heroes and self.monsters:
|
||||||
|
self.fight(self.heroes, self.monsters)
|
||||||
|
|
||||||
|
for monster in self.monsters:
|
||||||
|
if monster.HP < 0:
|
||||||
|
self.monsters.remove(monster)
|
||||||
|
|
||||||
|
if self.monsters:
|
||||||
|
self.fight(self.monsters, self.heroes, True)
|
||||||
|
|
||||||
|
for hero in self.heroes:
|
||||||
|
if hero.HP < 0:
|
||||||
|
self.heroes.remove(hero)
|
||||||
|
|
||||||
|
if self.heroes:
|
||||||
|
print("Congrats ! You passed next room")
|
||||||
|
elif self.monsters:
|
||||||
|
print(f"You {fg.red}lose{fg.rs}")
|
||||||
|
self.pveController.mController.close_game()
|
||||||
|
else:
|
||||||
|
raise Exception("An error occured")
|
||||||
|
|
||||||
|
def fight(
|
||||||
|
self,
|
||||||
|
heroes: list[Hero] | list[Monster],
|
||||||
|
opponents: list[Hero] | list[Monster],
|
||||||
|
is_ai_turn: bool = False,
|
||||||
|
):
|
||||||
|
heroes_list_len = len(heroes)
|
||||||
|
|
||||||
|
if heroes_list_len > 1:
|
||||||
|
choice = -1
|
||||||
|
while choice < 1 or choice > heroes_list_len:
|
||||||
|
if is_ai_turn:
|
||||||
|
choice = randint(1, heroes_list_len + 1)
|
||||||
|
else:
|
||||||
|
print("Who will attack?")
|
||||||
|
for i in range(0, heroes_list_len):
|
||||||
|
hero = heroes[i]
|
||||||
|
print(
|
||||||
|
f"{i+1} - {hero.name} | {hero.attack_power} {fg.red}Att{fg.rs} | {hero.defense} {fg.li_magenta}Blo{fg.rs} | {hero.HP}{fg.green} HP{fg.rs}"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > heroes_list_len:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again{fg.rs}")
|
||||||
|
|
||||||
|
choosen_hero = heroes[choice - 1]
|
||||||
|
print(f"{choosen_hero.name} will attack")
|
||||||
|
else:
|
||||||
|
choosen_hero = heroes[0]
|
||||||
|
|
||||||
|
opponents_list_len = len(opponents)
|
||||||
|
|
||||||
|
choice = -1
|
||||||
|
while choice < 1 or choice > opponents_list_len:
|
||||||
|
if is_ai_turn:
|
||||||
|
choice = randint(1, opponents_list_len + 1)
|
||||||
|
else:
|
||||||
|
print("Who do you want to attack?")
|
||||||
|
for i in range(0, opponents_list_len):
|
||||||
|
opponent = opponents[i]
|
||||||
|
print(
|
||||||
|
f"{i+1} - {opponent.name} | {opponent.attack_power} {fg.red}Att{fg.rs} | {opponent.defense} {fg.li_magenta}Blo{fg.rs} | {opponent.HP} {fg.green}HP{fg.rs}"
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > opponents_list_len:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again{fg.rs}")
|
||||||
|
|
||||||
|
choosen_opponent = opponents[choice - 1]
|
||||||
|
print(f"{choosen_hero.name} attacks {choosen_opponent.name}")
|
||||||
|
|
||||||
|
self.attacks(choosen_hero, choosen_opponent, is_ai_turn)
|
||||||
|
|
||||||
|
def attacks(self, hero: Hero, opponent: Monster, is_ai_turn: bool):
|
||||||
|
|
||||||
|
attacks_list = hero.attacks_choice
|
||||||
|
len_attack_list = len(attacks_list)
|
||||||
|
|
||||||
|
choice = -1
|
||||||
|
while choice < 1 or choice > len_attack_list:
|
||||||
|
if is_ai_turn:
|
||||||
|
choice = randint(1, len_attack_list + 1)
|
||||||
|
else:
|
||||||
|
print("Choose an attack")
|
||||||
|
for i in range(0, len_attack_list):
|
||||||
|
print(f"{i+1} - {attacks_list[i]}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > len_attack_list:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again{fg.rs}")
|
||||||
|
|
||||||
|
print(f"You choose {attacks_list[choice-1]}")
|
||||||
|
|
||||||
|
if choice == 1:
|
||||||
|
opponent.HP -= hero.attacks(opponent)
|
||||||
|
elif choice == 2:
|
||||||
|
hero.HP = hero.cure()
|
||||||
|
|
||||||
|
if opponent.HP > 0:
|
||||||
|
print(f"{opponent.name}: {opponent.HP} {fg.green}HP{fg.rs}")
|
||||||
|
else:
|
||||||
|
print(f"{opponent.name} is {fg.red}dead{fg.rs}")
|
||||||
84
views/PVP/arenaUI.py
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# arenaUI
|
||||||
|
|
||||||
|
# models
|
||||||
|
from models.heroes.hero import Hero
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from controllers.PvpController import PvpController
|
||||||
|
|
||||||
|
|
||||||
|
class ArenaUI:
|
||||||
|
def __init__(self, pvpController: "PvpController") -> None:
|
||||||
|
self.pvpController = pvpController
|
||||||
|
self.hero = self.pvpController.hero
|
||||||
|
self.opponent = self.pvpController.opponent
|
||||||
|
|
||||||
|
self.init()
|
||||||
|
|
||||||
|
self.pvpController.hero = self.hero
|
||||||
|
|
||||||
|
def init(self):
|
||||||
|
print("You go into the arena")
|
||||||
|
print(f"Are you {fg.green} ready {fg.rs} ?")
|
||||||
|
print("Anyway, no choice ^^")
|
||||||
|
|
||||||
|
print(f"You will {fg.red} fight {fg.red}against{self.opponent.name}")
|
||||||
|
|
||||||
|
if self.hero.type == Hero.ARCHERY:
|
||||||
|
print("You begin")
|
||||||
|
self.attacks(self.hero, self.opponent)
|
||||||
|
else:
|
||||||
|
print(f"{self.opponent.name} begin")
|
||||||
|
|
||||||
|
self.fight()
|
||||||
|
|
||||||
|
def fight(self):
|
||||||
|
while self.hero.HP > 0 and self.opponent.HP > 0:
|
||||||
|
self.attacks(self.hero, self.opponent)
|
||||||
|
|
||||||
|
if self.opponent.HP > 0:
|
||||||
|
self.attacks(self.opponent, self.hero, True)
|
||||||
|
|
||||||
|
if self.hero.HP > 0:
|
||||||
|
print(f"You {fg.blue}won{fg.rs} !")
|
||||||
|
elif self.opponent.HP > 0:
|
||||||
|
print(f"{self.opponent.name} {fg.red}beat{fg.rs} you")
|
||||||
|
else:
|
||||||
|
raise Exception("An error occured")
|
||||||
|
|
||||||
|
def attacks(self, hero: Hero, opponent: Hero, is_AI: bool = False):
|
||||||
|
print(f"Choose an attack - {hero.name} will ...")
|
||||||
|
|
||||||
|
attacks_list = hero.attacks_choice
|
||||||
|
attacks_list_len = len(attacks_list)
|
||||||
|
|
||||||
|
choice = -1
|
||||||
|
while choice < 1 or choice > attacks_list_len:
|
||||||
|
for i in range(0, attacks_list_len):
|
||||||
|
print(f"{i+1} - {attacks_list[i]}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if is_AI:
|
||||||
|
choice = randint(1, attacks_list_len + 1)
|
||||||
|
else:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > attacks_list_len:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again{fg.rs}")
|
||||||
|
|
||||||
|
print(f"You choose {attacks_list[choice-1]}")
|
||||||
|
|
||||||
|
if choice == 1:
|
||||||
|
opponent.HP -= hero.attacks(opponent)
|
||||||
|
elif choice == 2:
|
||||||
|
hero.cure()
|
||||||
123
views/PVP/chooseCharacterUI.py
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
# chooseCharacterUI
|
||||||
|
|
||||||
|
from models.loots.armor import Armor
|
||||||
|
from models.loots.weapon import Weapon
|
||||||
|
|
||||||
|
from sty import fg
|
||||||
|
|
||||||
|
from random import randint
|
||||||
|
|
||||||
|
# pour éviter les pb d'import circulaire
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from controllers.PvpController import PvpController
|
||||||
|
|
||||||
|
|
||||||
|
class ChooseCharacterUI:
|
||||||
|
def __init__(self, pvpController: "PvpController", is_AI: bool) -> None:
|
||||||
|
self.pvpController = pvpController
|
||||||
|
self.is_AI = is_AI
|
||||||
|
|
||||||
|
self.hero = None
|
||||||
|
|
||||||
|
self.set_character()
|
||||||
|
self.set_weapon()
|
||||||
|
self.set_armor()
|
||||||
|
|
||||||
|
def set_character(self):
|
||||||
|
heroes = self.pvpController.db.hero_db.get_all_heroes()
|
||||||
|
len_heroes = len(heroes)
|
||||||
|
|
||||||
|
print("Choose your character")
|
||||||
|
|
||||||
|
choice = -1 # Initialiser à une valeur qui n'est pas un index valide
|
||||||
|
while choice < 1 or choice > len_heroes:
|
||||||
|
for i in range(0, len_heroes):
|
||||||
|
hero = heroes[i]
|
||||||
|
print(f"{i+1}. {hero.get_type_str()} - {hero.name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.is_AI:
|
||||||
|
choice = randint(1, len_heroes)
|
||||||
|
else:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > len_heroes:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again {fg.rs}")
|
||||||
|
|
||||||
|
# L'indice dans la liste est `choice - 1`
|
||||||
|
# car choice commence à partir de 1
|
||||||
|
self.hero = heroes[choice - 1]
|
||||||
|
self.hero.name = fg.da_magenta + self.hero.name + fg.rs
|
||||||
|
|
||||||
|
print(f"You choose {self.hero.name}!")
|
||||||
|
|
||||||
|
def set_weapon(self):
|
||||||
|
weapons: list[Weapon] = self.pvpController.db.weapon_db.get_weapon_by_hero_type(
|
||||||
|
self.hero
|
||||||
|
)
|
||||||
|
len_weapons = len(weapons)
|
||||||
|
|
||||||
|
print("Choose your weapon now")
|
||||||
|
|
||||||
|
choice = -1
|
||||||
|
while choice < 1 or choice > len_weapons:
|
||||||
|
for i in range(0, len_weapons):
|
||||||
|
weapon = weapons[i]
|
||||||
|
print(f"{i+1}. {weapon.name} - {weapon.description}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.is_AI:
|
||||||
|
choice = randint(0, len_weapons)
|
||||||
|
else:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red} Input a valid number {fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > len_weapons:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again {fg.rs}")
|
||||||
|
|
||||||
|
# L'indice dans la liste est `choice - 1`
|
||||||
|
# car choice commence à partir de 1
|
||||||
|
self.hero.weapon = weapons[choice - 1]
|
||||||
|
self.hero.weapon.name = fg.da_magenta + self.hero.weapon.name + fg.rs
|
||||||
|
|
||||||
|
print(f"You choose the weapon: {self.hero.weapon.name}")
|
||||||
|
|
||||||
|
def set_armor(self):
|
||||||
|
armors: list[Armor] = self.pvpController.db.armor_db.get_armor_by_hero_type(
|
||||||
|
self.hero
|
||||||
|
)
|
||||||
|
len_armors = len(armors)
|
||||||
|
|
||||||
|
print("Now, choose your armor")
|
||||||
|
|
||||||
|
choice = -1
|
||||||
|
while choice < 1 or choice > len_armors:
|
||||||
|
for i in range(0, len_armors):
|
||||||
|
armor = armors[i]
|
||||||
|
print(f"{i+1}. {armor.name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
if self.is_AI:
|
||||||
|
choice = randint(1, len_armors)
|
||||||
|
else:
|
||||||
|
choice = int(input("Give your choice: "))
|
||||||
|
except ValueError:
|
||||||
|
print(f"{fg.red}Input a valid number{fg.rs}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
if choice < 1 or choice > len_armors:
|
||||||
|
print(f"{fg.red}Invalid choice. Try again{fg.rs}")
|
||||||
|
|
||||||
|
# L'indice dans la liste est `choice - 1`
|
||||||
|
# car choice commence à partir de 1
|
||||||
|
self.hero.armor = armors[choice - 1]
|
||||||
|
self.hero.armor.name = fg.da_magenta + self.hero.armor.name + fg.rs
|
||||||
|
|
||||||
|
print(f"You choose {self.hero.armor.name}")
|
||||||