multiplayer 0.11.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- multiplayer/IPClogging/__init__.py +42 -0
- multiplayer/IPClogging/echoing.py +34 -0
- multiplayer/IPClogging/server.py +338 -0
- multiplayer/IPClogging/test.py +71 -0
- multiplayer/__init__.py +52 -0
- multiplayer/client.py +531 -0
- multiplayer/data/__init__.py +1 -0
- multiplayer/data/cities.csv +103 -0
- multiplayer/data/countries.csv +152 -0
- multiplayer/data/egyptian_gods.csv +110 -0
- multiplayer/data/european_kings.csv +109 -0
- multiplayer/data/european_queens.csv +105 -0
- multiplayer/data/greek_gods.csv +122 -0
- multiplayer/data/planets_moons.csv +123 -0
- multiplayer/data/rivers.csv +103 -0
- multiplayer/data/roman_gods.csv +109 -0
- multiplayer/data/seas_oceans.csv +104 -0
- multiplayer/exceptions.py +39 -0
- multiplayer/game.py +275 -0
- multiplayer/language/__init__.py +23 -0
- multiplayer/language/language.py +445 -0
- multiplayer/py.typed +0 -0
- multiplayer/run_log_server.py +33 -0
- multiplayer/run_server.py +91 -0
- multiplayer/server.py +676 -0
- multiplayer/utils.py +215 -0
- multiplayer-0.11.0.dist-info/METADATA +284 -0
- multiplayer-0.11.0.dist-info/RECORD +31 -0
- multiplayer-0.11.0.dist-info/WHEEL +4 -0
- multiplayer-0.11.0.dist-info/entry_points.txt +4 -0
- multiplayer-0.11.0.dist-info/licenses/LICENSE.md +23 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
name
|
|
2
|
+
Nile
|
|
3
|
+
Amazon
|
|
4
|
+
Yangtze
|
|
5
|
+
Mississippi
|
|
6
|
+
Yenisei
|
|
7
|
+
Yellow River
|
|
8
|
+
Ob
|
|
9
|
+
Parana
|
|
10
|
+
Congo
|
|
11
|
+
Amur
|
|
12
|
+
Lena
|
|
13
|
+
Mekong
|
|
14
|
+
Mackenzie
|
|
15
|
+
Niger
|
|
16
|
+
Murray
|
|
17
|
+
Tocantins
|
|
18
|
+
Volga
|
|
19
|
+
Shatt al-Arab
|
|
20
|
+
Madeira
|
|
21
|
+
Purus
|
|
22
|
+
Yukon
|
|
23
|
+
Indus
|
|
24
|
+
Sao Francisco
|
|
25
|
+
Syr Darya
|
|
26
|
+
Salween
|
|
27
|
+
Saint Lawrence
|
|
28
|
+
Rio Grande
|
|
29
|
+
Lower Tunguska
|
|
30
|
+
Brahmaputra
|
|
31
|
+
Danube
|
|
32
|
+
Zambezi
|
|
33
|
+
Vilyuy
|
|
34
|
+
Araguaia
|
|
35
|
+
Nelson
|
|
36
|
+
Paraguay
|
|
37
|
+
Kolyma
|
|
38
|
+
Ganges
|
|
39
|
+
Amu Darya
|
|
40
|
+
Japura
|
|
41
|
+
Ural
|
|
42
|
+
Arkansas
|
|
43
|
+
Colorado
|
|
44
|
+
Dnieper
|
|
45
|
+
Aldan
|
|
46
|
+
Ubangi
|
|
47
|
+
Negro
|
|
48
|
+
Orinoco
|
|
49
|
+
Irtysh
|
|
50
|
+
Xingu
|
|
51
|
+
Salado
|
|
52
|
+
Tigris
|
|
53
|
+
Songhua
|
|
54
|
+
Tapajos
|
|
55
|
+
Don
|
|
56
|
+
Pechora
|
|
57
|
+
Kama
|
|
58
|
+
Liao
|
|
59
|
+
Zeya
|
|
60
|
+
Kasai
|
|
61
|
+
Ohio
|
|
62
|
+
Iriri
|
|
63
|
+
Tarim
|
|
64
|
+
Vitim
|
|
65
|
+
Tunguska
|
|
66
|
+
Euphrates
|
|
67
|
+
Godavari
|
|
68
|
+
Krishna
|
|
69
|
+
Indigirka
|
|
70
|
+
Saskatchewan
|
|
71
|
+
Peace
|
|
72
|
+
Orange
|
|
73
|
+
Olenyok
|
|
74
|
+
Jubba
|
|
75
|
+
Magdalena
|
|
76
|
+
Lomami
|
|
77
|
+
Ogooue
|
|
78
|
+
Pecos
|
|
79
|
+
Kura
|
|
80
|
+
Columbia
|
|
81
|
+
Sankuru
|
|
82
|
+
Ishim
|
|
83
|
+
Jialing
|
|
84
|
+
Benue
|
|
85
|
+
Guapore
|
|
86
|
+
Yamuna
|
|
87
|
+
Senegal
|
|
88
|
+
Churchill
|
|
89
|
+
Tobol
|
|
90
|
+
Alazeya
|
|
91
|
+
Han
|
|
92
|
+
Khatanga
|
|
93
|
+
Olekma
|
|
94
|
+
Platte
|
|
95
|
+
Trisuli
|
|
96
|
+
Ica
|
|
97
|
+
Mara
|
|
98
|
+
Vaal
|
|
99
|
+
Okavango
|
|
100
|
+
Limpopo
|
|
101
|
+
Helmand
|
|
102
|
+
Cunene
|
|
103
|
+
Chari
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
name
|
|
2
|
+
Jupiter
|
|
3
|
+
Juno
|
|
4
|
+
Neptune
|
|
5
|
+
Minerva
|
|
6
|
+
Apollo
|
|
7
|
+
Diana
|
|
8
|
+
Mars
|
|
9
|
+
Venus
|
|
10
|
+
Mercury
|
|
11
|
+
Vesta
|
|
12
|
+
Ceres
|
|
13
|
+
Vulcan
|
|
14
|
+
Bacchus
|
|
15
|
+
Pluto
|
|
16
|
+
Proserpina
|
|
17
|
+
Saturn
|
|
18
|
+
Uranus
|
|
19
|
+
Janus
|
|
20
|
+
Cupid
|
|
21
|
+
Psyche
|
|
22
|
+
Sol
|
|
23
|
+
Luna
|
|
24
|
+
Fortuna
|
|
25
|
+
Victoria
|
|
26
|
+
Concordia
|
|
27
|
+
Fides
|
|
28
|
+
Spes
|
|
29
|
+
Salus
|
|
30
|
+
Pax
|
|
31
|
+
Libertas
|
|
32
|
+
Honos
|
|
33
|
+
Virtus
|
|
34
|
+
Pietas
|
|
35
|
+
Felicitas
|
|
36
|
+
Genius
|
|
37
|
+
Lares
|
|
38
|
+
Penates
|
|
39
|
+
Manes
|
|
40
|
+
Faunus
|
|
41
|
+
Flora
|
|
42
|
+
Pomona
|
|
43
|
+
Vertumnus
|
|
44
|
+
Terminus
|
|
45
|
+
Consus
|
|
46
|
+
Ops
|
|
47
|
+
Portunus
|
|
48
|
+
Carmenta
|
|
49
|
+
Bellona
|
|
50
|
+
Quirinus
|
|
51
|
+
Volturnus
|
|
52
|
+
Tiberinus
|
|
53
|
+
Aesculapius
|
|
54
|
+
Hercules
|
|
55
|
+
Castor
|
|
56
|
+
Pollux
|
|
57
|
+
Aeneas
|
|
58
|
+
Romulus
|
|
59
|
+
Remus
|
|
60
|
+
Numa
|
|
61
|
+
Camenae
|
|
62
|
+
Egeria
|
|
63
|
+
Muses
|
|
64
|
+
Graces
|
|
65
|
+
Fates
|
|
66
|
+
Furies
|
|
67
|
+
Horae
|
|
68
|
+
Nymphs
|
|
69
|
+
Sylvanus
|
|
70
|
+
Tellus
|
|
71
|
+
Maia
|
|
72
|
+
Acca Larentia
|
|
73
|
+
Anna Perenna
|
|
74
|
+
Cardea
|
|
75
|
+
Carna
|
|
76
|
+
Clementia
|
|
77
|
+
Disciplina
|
|
78
|
+
Eventus Bonus
|
|
79
|
+
Febris
|
|
80
|
+
Feronia
|
|
81
|
+
Fons
|
|
82
|
+
Furrina
|
|
83
|
+
Justitia
|
|
84
|
+
Laetitia
|
|
85
|
+
Laverna
|
|
86
|
+
Libitina
|
|
87
|
+
Mellona
|
|
88
|
+
Muta
|
|
89
|
+
Nemesis
|
|
90
|
+
Nox
|
|
91
|
+
Pales
|
|
92
|
+
Robigo
|
|
93
|
+
Rumina
|
|
94
|
+
Rusina
|
|
95
|
+
Securitas
|
|
96
|
+
Trivia
|
|
97
|
+
Veritas
|
|
98
|
+
Voluptas
|
|
99
|
+
Volturna
|
|
100
|
+
Angerona
|
|
101
|
+
Bubona
|
|
102
|
+
Candelifera
|
|
103
|
+
Lucina
|
|
104
|
+
Mena
|
|
105
|
+
Nascio
|
|
106
|
+
Partula
|
|
107
|
+
Strenia
|
|
108
|
+
Viduus
|
|
109
|
+
Volumnus
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
name
|
|
2
|
+
Pacific Ocean
|
|
3
|
+
Atlantic Ocean
|
|
4
|
+
Indian Ocean
|
|
5
|
+
Arctic Ocean
|
|
6
|
+
Southern Ocean
|
|
7
|
+
Mediterranean Sea
|
|
8
|
+
Caribbean Sea
|
|
9
|
+
South China Sea
|
|
10
|
+
Bering Sea
|
|
11
|
+
Gulf of Mexico
|
|
12
|
+
Okhotsk Sea
|
|
13
|
+
East China Sea
|
|
14
|
+
Hudson Bay
|
|
15
|
+
Japan Sea
|
|
16
|
+
Andaman Sea
|
|
17
|
+
North Sea
|
|
18
|
+
Red Sea
|
|
19
|
+
Baltic Sea
|
|
20
|
+
Black Sea
|
|
21
|
+
Arabian Sea
|
|
22
|
+
Coral Sea
|
|
23
|
+
Tasman Sea
|
|
24
|
+
Philippine Sea
|
|
25
|
+
Sargasso Sea
|
|
26
|
+
Greenland Sea
|
|
27
|
+
Barents Sea
|
|
28
|
+
Kara Sea
|
|
29
|
+
Laptev Sea
|
|
30
|
+
East Siberian Sea
|
|
31
|
+
Chukchi Sea
|
|
32
|
+
Beaufort Sea
|
|
33
|
+
Lincoln Sea
|
|
34
|
+
Wandel Sea
|
|
35
|
+
Norwegian Sea
|
|
36
|
+
Irish Sea
|
|
37
|
+
Celtic Sea
|
|
38
|
+
English Channel
|
|
39
|
+
Bay of Biscay
|
|
40
|
+
Adriatic Sea
|
|
41
|
+
Aegean Sea
|
|
42
|
+
Ionian Sea
|
|
43
|
+
Tyrrhenian Sea
|
|
44
|
+
Ligurian Sea
|
|
45
|
+
Alboran Sea
|
|
46
|
+
Balearic Sea
|
|
47
|
+
Sea of Crete
|
|
48
|
+
Sea of Marmara
|
|
49
|
+
Sea of Azov
|
|
50
|
+
Caspian Sea
|
|
51
|
+
Aral Sea
|
|
52
|
+
Salton Sea
|
|
53
|
+
Dead Sea
|
|
54
|
+
Sea of Galilee
|
|
55
|
+
White Sea
|
|
56
|
+
Pechora Sea
|
|
57
|
+
Timor Sea
|
|
58
|
+
Arafura Sea
|
|
59
|
+
Banda Sea
|
|
60
|
+
Celebes Sea
|
|
61
|
+
Sulu Sea
|
|
62
|
+
Molucca Sea
|
|
63
|
+
Java Sea
|
|
64
|
+
Flores Sea
|
|
65
|
+
Savu Sea
|
|
66
|
+
Halmahera Sea
|
|
67
|
+
Ceram Sea
|
|
68
|
+
Bismarck Sea
|
|
69
|
+
Solomon Sea
|
|
70
|
+
Gulf of Carpentaria
|
|
71
|
+
Gulf of Thailand
|
|
72
|
+
Gulf of Tonkin
|
|
73
|
+
Yellow Sea
|
|
74
|
+
Bohai Sea
|
|
75
|
+
Seto Inland Sea
|
|
76
|
+
Sea of Japan
|
|
77
|
+
Gulf of Alaska
|
|
78
|
+
Gulf of California
|
|
79
|
+
Labrador Sea
|
|
80
|
+
Irminger Sea
|
|
81
|
+
Davis Strait
|
|
82
|
+
Baffin Bay
|
|
83
|
+
James Bay
|
|
84
|
+
Gulf of St. Lawrence
|
|
85
|
+
Bay of Fundy
|
|
86
|
+
Sunda Strait
|
|
87
|
+
Makassar Strait
|
|
88
|
+
Lombok Strait
|
|
89
|
+
Malacca Strait
|
|
90
|
+
Singapore Strait
|
|
91
|
+
Palk Strait
|
|
92
|
+
Bab-el-Mandeb
|
|
93
|
+
Strait of Hormuz
|
|
94
|
+
Persian Gulf
|
|
95
|
+
Gulf of Oman
|
|
96
|
+
Gulf of Aden
|
|
97
|
+
Gulf of Guinea
|
|
98
|
+
Mozambique Channel
|
|
99
|
+
Great Australian Bight
|
|
100
|
+
Spencer Gulf
|
|
101
|
+
Gulf St Vincent
|
|
102
|
+
Bass Strait
|
|
103
|
+
Cook Strait
|
|
104
|
+
Foveaux Strait
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Custom exceptions for the multiplayer module.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
class MultiplayerError(Exception):
|
|
6
|
+
"""Base class for exceptions in this module."""
|
|
7
|
+
pass
|
|
8
|
+
|
|
9
|
+
class GameLogicError(MultiplayerError):
|
|
10
|
+
"""Raised for errors in game logic (e.g., starting a game with no players)."""
|
|
11
|
+
pass
|
|
12
|
+
|
|
13
|
+
class PlayerLimitReachedError(GameLogicError):
|
|
14
|
+
"""Raised when trying to add a player to a full game."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
class ObserverLimitReachedError(GameLogicError):
|
|
18
|
+
"""Raised when trying to add an observer to a full game."""
|
|
19
|
+
pass
|
|
20
|
+
|
|
21
|
+
class GameNotFoundError(MultiplayerError):
|
|
22
|
+
"""Raised when a game_id is not found on the server."""
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
class NetworkError(MultiplayerError):
|
|
26
|
+
"""Base class for network-related errors."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
class ConnectionError(NetworkError):
|
|
30
|
+
"""Raised for errors connecting to the server."""
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
class ServerError(NetworkError):
|
|
34
|
+
"""Raised when the server reports a generic internal error."""
|
|
35
|
+
pass
|
|
36
|
+
|
|
37
|
+
class AuthenticationError(NetworkError):
|
|
38
|
+
"""Raised for password authentication failures."""
|
|
39
|
+
pass
|
multiplayer/game.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides classes for managing a multiplayer game.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import enum
|
|
6
|
+
import uuid
|
|
7
|
+
from .exceptions import GameLogicError, PlayerLimitReachedError, ObserverLimitReachedError, AuthenticationError
|
|
8
|
+
|
|
9
|
+
class GameState(enum.Enum):
|
|
10
|
+
"""
|
|
11
|
+
Represents the state of the game.
|
|
12
|
+
"""
|
|
13
|
+
PENDING = "pending"
|
|
14
|
+
IN_PROGRESS = "in_progress"
|
|
15
|
+
FINISHED = "finished"
|
|
16
|
+
|
|
17
|
+
class Player:
|
|
18
|
+
"""
|
|
19
|
+
Represents a player in the game.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
name (str): The name of the player.
|
|
23
|
+
id (str, optional): The player's ID.
|
|
24
|
+
**kwargs: Additional attributes for the player.
|
|
25
|
+
"""
|
|
26
|
+
def __init__(self, name, id=None, **kwargs):
|
|
27
|
+
self.name = name
|
|
28
|
+
self.attributes = kwargs
|
|
29
|
+
self._id = id or str(uuid.uuid4())
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def ID(self):
|
|
33
|
+
"""
|
|
34
|
+
The unique ID of the player.
|
|
35
|
+
"""
|
|
36
|
+
return self._id
|
|
37
|
+
|
|
38
|
+
class GameGroup:
|
|
39
|
+
"""
|
|
40
|
+
Represents a group of games on a server.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
name (str): The name of the group.
|
|
44
|
+
admin_password (str, optional): A password for administrative actions on this group.
|
|
45
|
+
**kwargs: Additional attributes for the group.
|
|
46
|
+
"""
|
|
47
|
+
def __init__(self, name, admin_password=None, **kwargs):
|
|
48
|
+
self.name = name
|
|
49
|
+
self.admin_password = admin_password
|
|
50
|
+
self.attributes = kwargs
|
|
51
|
+
self.games = []
|
|
52
|
+
self._id = str(uuid.uuid4())
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def ID(self):
|
|
56
|
+
"""
|
|
57
|
+
The unique ID of the group.
|
|
58
|
+
"""
|
|
59
|
+
return self._id
|
|
60
|
+
|
|
61
|
+
def add_game(self, game):
|
|
62
|
+
"""
|
|
63
|
+
Adds a game to the group.
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
game (Game): The game to add.
|
|
67
|
+
"""
|
|
68
|
+
if game not in self.games:
|
|
69
|
+
self.games.append(game)
|
|
70
|
+
|
|
71
|
+
def remove_game(self, game_id):
|
|
72
|
+
"""
|
|
73
|
+
Removes a game from the group by ID.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
game_id (str): The ID of the game to remove.
|
|
77
|
+
"""
|
|
78
|
+
game_to_remove = next((g for g in self.games if g.ID == game_id), None)
|
|
79
|
+
if game_to_remove:
|
|
80
|
+
self.games.remove(game_to_remove)
|
|
81
|
+
|
|
82
|
+
class Observer:
|
|
83
|
+
"""
|
|
84
|
+
Represents an observer in the game.
|
|
85
|
+
|
|
86
|
+
Args:
|
|
87
|
+
name (str): The name of the observer.
|
|
88
|
+
id (str, optional): The observer's ID.
|
|
89
|
+
**kwargs: Additional attributes for the observer.
|
|
90
|
+
"""
|
|
91
|
+
def __init__(self, name, id=None, **kwargs):
|
|
92
|
+
self.name = name
|
|
93
|
+
self.attributes = kwargs
|
|
94
|
+
self._id = id or str(uuid.uuid4())
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def ID(self):
|
|
98
|
+
"""
|
|
99
|
+
The unique ID of the observer.
|
|
100
|
+
"""
|
|
101
|
+
return self._id
|
|
102
|
+
|
|
103
|
+
class Game:
|
|
104
|
+
"""
|
|
105
|
+
Represents a multiplayer game.
|
|
106
|
+
|
|
107
|
+
Args:
|
|
108
|
+
name (str, optional): The name of the game session. Defaults to None.
|
|
109
|
+
max_players (int, optional): The maximum number of players allowed in the game. Defaults to None.
|
|
110
|
+
max_observers (int, optional): The maximum number of observers allowed in the game. Defaults to None.
|
|
111
|
+
turn_based (bool, optional): Whether the game is turn-based or simultaneous. Defaults to False.
|
|
112
|
+
password (str, optional): A password to protect this specific game.
|
|
113
|
+
**kwargs: Additional attributes for the game.
|
|
114
|
+
"""
|
|
115
|
+
def __init__(self, name=None, max_players=None, max_observers=None, turn_based=False, password=None, observer_password=None, **kwargs):
|
|
116
|
+
self.name = name
|
|
117
|
+
self.max_players = max_players
|
|
118
|
+
self.max_observers = max_observers
|
|
119
|
+
self.turn_based = turn_based
|
|
120
|
+
self.password = password
|
|
121
|
+
self.observer_password = observer_password
|
|
122
|
+
self.attributes = kwargs
|
|
123
|
+
self.players = []
|
|
124
|
+
self.observers = []
|
|
125
|
+
self.state = GameState.PENDING
|
|
126
|
+
self.current_player_index = 0
|
|
127
|
+
self.custom_state = {}
|
|
128
|
+
self._id = str(uuid.uuid4())
|
|
129
|
+
|
|
130
|
+
@property
|
|
131
|
+
def ID(self):
|
|
132
|
+
"""
|
|
133
|
+
The unique ID of the game.
|
|
134
|
+
"""
|
|
135
|
+
return self._id
|
|
136
|
+
|
|
137
|
+
def add_player(self, player, password=None):
|
|
138
|
+
"""
|
|
139
|
+
Adds a player to the game.
|
|
140
|
+
|
|
141
|
+
Args:
|
|
142
|
+
player (Player): The player to add.
|
|
143
|
+
password (str, optional): The password required to join the game.
|
|
144
|
+
|
|
145
|
+
Raises:
|
|
146
|
+
AuthenticationError: If the provided password does not match the game's password.
|
|
147
|
+
PlayerLimitReachedError: If the maximum number of players has been reached.
|
|
148
|
+
"""
|
|
149
|
+
if self.password is not None and self.password != password:
|
|
150
|
+
raise AuthenticationError("Invalid password for this game")
|
|
151
|
+
if self.max_players is not None and len(self.players) >= self.max_players:
|
|
152
|
+
raise PlayerLimitReachedError("Maximum number of players reached")
|
|
153
|
+
self.players.append(player)
|
|
154
|
+
|
|
155
|
+
def add_observer(self, observer, password=None):
|
|
156
|
+
"""
|
|
157
|
+
Adds an observer to the game.
|
|
158
|
+
|
|
159
|
+
Args:
|
|
160
|
+
observer (Observer): The observer to add.
|
|
161
|
+
password (str, optional): The password required to join the game as an observer.
|
|
162
|
+
|
|
163
|
+
Raises:
|
|
164
|
+
AuthenticationError: If the provided password does not match the observer password (or game password if no observer password is set).
|
|
165
|
+
ObserverLimitReachedError: If the maximum number of observers has been reached.
|
|
166
|
+
"""
|
|
167
|
+
required_password = self.observer_password if self.observer_password is not None else self.password
|
|
168
|
+
if required_password is not None and required_password != password:
|
|
169
|
+
raise AuthenticationError("Invalid password for this game")
|
|
170
|
+
if self.max_observers is not None and len(self.observers) >= self.max_observers:
|
|
171
|
+
raise ObserverLimitReachedError("Maximum number of observers reached")
|
|
172
|
+
self.observers.append(observer)
|
|
173
|
+
|
|
174
|
+
def remove_player(self, player_id):
|
|
175
|
+
"""
|
|
176
|
+
Removes a player from the game by ID.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
player_id (str): The ID of the player to remove.
|
|
180
|
+
"""
|
|
181
|
+
player_to_remove = next((p for p in self.players if p.ID == player_id), None)
|
|
182
|
+
if player_to_remove:
|
|
183
|
+
removed_player_index = self.players.index(player_to_remove)
|
|
184
|
+
self.players.remove(player_to_remove)
|
|
185
|
+
|
|
186
|
+
if self.turn_based and self.state == GameState.IN_PROGRESS:
|
|
187
|
+
if not self.players:
|
|
188
|
+
self.state = GameState.PENDING
|
|
189
|
+
elif self.current_player_index >= removed_player_index:
|
|
190
|
+
self.current_player_index = self.current_player_index % len(self.players)
|
|
191
|
+
|
|
192
|
+
def remove_observer(self, observer_id):
|
|
193
|
+
"""
|
|
194
|
+
Removes an observer from the game by ID.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
observer_id (str): The ID of the observer to remove.
|
|
198
|
+
"""
|
|
199
|
+
observer_to_remove = next((o for o in self.observers if o.ID == observer_id), None)
|
|
200
|
+
if observer_to_remove:
|
|
201
|
+
self.observers.remove(observer_to_remove)
|
|
202
|
+
|
|
203
|
+
def start(self):
|
|
204
|
+
"""
|
|
205
|
+
Starts the game.
|
|
206
|
+
|
|
207
|
+
Raises:
|
|
208
|
+
GameLogicError: If there are no players in the game or if the game is already in progress.
|
|
209
|
+
"""
|
|
210
|
+
if self.state == GameState.IN_PROGRESS:
|
|
211
|
+
raise GameLogicError("Game is already in progress")
|
|
212
|
+
if not self.players:
|
|
213
|
+
raise GameLogicError("Cannot start a game with no players")
|
|
214
|
+
self.state = GameState.IN_PROGRESS
|
|
215
|
+
|
|
216
|
+
def pause(self):
|
|
217
|
+
"""
|
|
218
|
+
Pauses the game.
|
|
219
|
+
|
|
220
|
+
Raises:
|
|
221
|
+
GameLogicError: If the game is not in progress.
|
|
222
|
+
"""
|
|
223
|
+
if self.state != GameState.IN_PROGRESS:
|
|
224
|
+
raise GameLogicError("Game is not in progress")
|
|
225
|
+
self.state = GameState.PENDING
|
|
226
|
+
|
|
227
|
+
def resume(self):
|
|
228
|
+
"""
|
|
229
|
+
Resumes the game.
|
|
230
|
+
|
|
231
|
+
Raises:
|
|
232
|
+
GameLogicError: If the game is not pending.
|
|
233
|
+
"""
|
|
234
|
+
if self.state != GameState.PENDING:
|
|
235
|
+
raise GameLogicError("Game is not pending")
|
|
236
|
+
self.state = GameState.IN_PROGRESS
|
|
237
|
+
|
|
238
|
+
def stop(self):
|
|
239
|
+
"""
|
|
240
|
+
Stops the game.
|
|
241
|
+
"""
|
|
242
|
+
self.state = GameState.FINISHED
|
|
243
|
+
|
|
244
|
+
def next_turn(self):
|
|
245
|
+
"""
|
|
246
|
+
Advances to the next turn in a turn-based game.
|
|
247
|
+
|
|
248
|
+
Raises:
|
|
249
|
+
GameLogicError: If the game is not turn-based or not in progress.
|
|
250
|
+
"""
|
|
251
|
+
if not self.turn_based:
|
|
252
|
+
raise GameLogicError("Game is not turn-based")
|
|
253
|
+
if self.state != GameState.IN_PROGRESS:
|
|
254
|
+
raise GameLogicError("Game is not in progress")
|
|
255
|
+
if self.players:
|
|
256
|
+
self.current_player_index = (self.current_player_index + 1) % len(self.players)
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def current_player(self):
|
|
260
|
+
"""
|
|
261
|
+
The current player in a turn-based game.
|
|
262
|
+
|
|
263
|
+
Returns:
|
|
264
|
+
Player: The current player.
|
|
265
|
+
|
|
266
|
+
Raises:
|
|
267
|
+
GameLogicError: If the game is not turn-based or not in progress.
|
|
268
|
+
"""
|
|
269
|
+
if not self.turn_based:
|
|
270
|
+
raise GameLogicError("Game is not turn-based")
|
|
271
|
+
if self.state != GameState.IN_PROGRESS:
|
|
272
|
+
raise GameLogicError("Game is not in progress")
|
|
273
|
+
if not self.players:
|
|
274
|
+
return None
|
|
275
|
+
return self.players[self.current_player_index]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
multiplayer, a Python library for managing multiplayer games
|
|
3
|
+
Copyright (C) 2025 [devfred78](https://github.com/devfred78)
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
|
|
18
|
+
This package provides tools for managing interface languages.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from .language import Language, Languages
|
|
22
|
+
|
|
23
|
+
__all__ = ["Language", "Languages"]
|