rom24-quickmud-python 1.2.2__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.
- mud/__init__.py +0 -0
- mud/__main__.py +40 -0
- mud/account/__init__.py +20 -0
- mud/account/account_manager.py +62 -0
- mud/account/account_service.py +80 -0
- mud/advancement.py +62 -0
- mud/affects/saves.py +123 -0
- mud/agent/__init__.py +0 -0
- mud/agent/agent_protocol.py +19 -0
- mud/agent/character_agent.py +61 -0
- mud/combat/__init__.py +3 -0
- mud/combat/engine.py +189 -0
- mud/commands/__init__.py +3 -0
- mud/commands/admin_commands.py +77 -0
- mud/commands/advancement.py +36 -0
- mud/commands/alias_cmds.py +44 -0
- mud/commands/build.py +18 -0
- mud/commands/combat.py +16 -0
- mud/commands/communication.py +55 -0
- mud/commands/decorators.py +11 -0
- mud/commands/dispatcher.py +206 -0
- mud/commands/healer.py +81 -0
- mud/commands/help.py +14 -0
- mud/commands/imc.py +19 -0
- mud/commands/inspection.py +113 -0
- mud/commands/inventory.py +42 -0
- mud/commands/movement.py +71 -0
- mud/commands/notes.py +44 -0
- mud/commands/shop.py +138 -0
- mud/commands/socials.py +34 -0
- mud/config.py +59 -0
- mud/db/__init__.py +0 -0
- mud/db/init.py +27 -0
- mud/db/migrate_from_files.py +87 -0
- mud/db/migrations.py +7 -0
- mud/db/models.py +98 -0
- mud/db/seed.py +28 -0
- mud/db/session.py +11 -0
- mud/devtools/__init__.py +0 -0
- mud/devtools/agent_demo.py +19 -0
- mud/entrypoint.py +34 -0
- mud/game_loop.py +117 -0
- mud/imc/__init__.py +17 -0
- mud/imc/protocol.py +32 -0
- mud/loaders/__init__.py +27 -0
- mud/loaders/area_loader.py +73 -0
- mud/loaders/base_loader.py +38 -0
- mud/loaders/help_loader.py +17 -0
- mud/loaders/json_area_loader.py +203 -0
- mud/loaders/json_loader.py +285 -0
- mud/loaders/mob_loader.py +104 -0
- mud/loaders/obj_loader.py +76 -0
- mud/loaders/reset_loader.py +29 -0
- mud/loaders/room_loader.py +63 -0
- mud/loaders/shop_loader.py +41 -0
- mud/loaders/social_loader.py +16 -0
- mud/loaders/specials_loader.py +63 -0
- mud/logging/__init__.py +0 -0
- mud/logging/admin.py +40 -0
- mud/logging/agent_trace.py +9 -0
- mud/math/c_compat.py +27 -0
- mud/mobprog.py +72 -0
- mud/models/__init__.py +106 -0
- mud/models/area.py +33 -0
- mud/models/area_json.py +27 -0
- mud/models/board.py +49 -0
- mud/models/board_json.py +16 -0
- mud/models/character.py +195 -0
- mud/models/character_json.py +46 -0
- mud/models/constants.py +423 -0
- mud/models/conversion.py +45 -0
- mud/models/help.py +28 -0
- mud/models/help_json.py +14 -0
- mud/models/json_io.py +64 -0
- mud/models/mob.py +82 -0
- mud/models/note.py +29 -0
- mud/models/note_json.py +16 -0
- mud/models/obj.py +82 -0
- mud/models/object.py +28 -0
- mud/models/object_json.py +40 -0
- mud/models/player_json.py +29 -0
- mud/models/room.py +86 -0
- mud/models/room_json.py +46 -0
- mud/models/shop.py +21 -0
- mud/models/shop_json.py +17 -0
- mud/models/skill.py +25 -0
- mud/models/skill_json.py +20 -0
- mud/models/social.py +78 -0
- mud/models/social_json.py +20 -0
- mud/net/__init__.py +9 -0
- mud/net/ansi.py +27 -0
- mud/net/connection.py +174 -0
- mud/net/protocol.py +57 -0
- mud/net/session.py +21 -0
- mud/net/telnet_server.py +31 -0
- mud/network/__init__.py +0 -0
- mud/network/websocket_server.py +83 -0
- mud/network/websocket_session.py +21 -0
- mud/notes.py +45 -0
- mud/persistence.py +185 -0
- mud/registry.py +5 -0
- mud/scripts/convert_are_to_json.py +162 -0
- mud/scripts/convert_help_are_to_json.py +92 -0
- mud/scripts/convert_player_to_json.py +112 -0
- mud/scripts/convert_shops_to_json.py +64 -0
- mud/scripts/convert_skills_to_json.py +166 -0
- mud/scripts/convert_social_are_to_json.py +92 -0
- mud/scripts/load_test_data.py +17 -0
- mud/security/__init__.py +0 -0
- mud/security/bans.py +112 -0
- mud/security/hash_utils.py +20 -0
- mud/server.py +8 -0
- mud/skills/__init__.py +3 -0
- mud/skills/handlers.py +795 -0
- mud/skills/registry.py +97 -0
- mud/spawning/__init__.py +1 -0
- mud/spawning/mob_spawner.py +13 -0
- mud/spawning/obj_spawner.py +18 -0
- mud/spawning/reset_handler.py +222 -0
- mud/spawning/templates.py +63 -0
- mud/spec_funs.py +57 -0
- mud/time.py +48 -0
- mud/utils/rng_mm.py +123 -0
- mud/wiznet.py +74 -0
- mud/world/__init__.py +11 -0
- mud/world/linking.py +31 -0
- mud/world/look.py +29 -0
- mud/world/movement.py +135 -0
- mud/world/world_state.py +179 -0
- rom24_quickmud_python-1.2.2.dist-info/METADATA +236 -0
- rom24_quickmud_python-1.2.2.dist-info/RECORD +135 -0
- rom24_quickmud_python-1.2.2.dist-info/WHEEL +5 -0
- rom24_quickmud_python-1.2.2.dist-info/entry_points.txt +2 -0
- rom24_quickmud_python-1.2.2.dist-info/licenses/LICENSE +21 -0
- rom24_quickmud_python-1.2.2.dist-info/top_level.txt +1 -0
mud/models/help.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from .help_json import HelpJson
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class HelpEntry:
|
|
10
|
+
"""Runtime representation of a help entry."""
|
|
11
|
+
|
|
12
|
+
keywords: list[str]
|
|
13
|
+
text: str
|
|
14
|
+
level: int = 0
|
|
15
|
+
|
|
16
|
+
@classmethod
|
|
17
|
+
def from_json(cls, data: HelpJson) -> "HelpEntry":
|
|
18
|
+
return cls(**data.to_dict())
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# placeholder registry to track loaded help entries
|
|
22
|
+
help_registry: dict[str, HelpEntry] = {}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def register_help(entry: HelpEntry) -> None:
|
|
26
|
+
"""Register a help entry under each keyword."""
|
|
27
|
+
for keyword in entry.keywords:
|
|
28
|
+
help_registry[keyword.lower()] = entry
|
mud/models/help_json.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from .json_io import JsonDataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class HelpJson(JsonDataclass):
|
|
10
|
+
"""Help entry matching ``schemas/help.schema.json``."""
|
|
11
|
+
|
|
12
|
+
keywords: list[str]
|
|
13
|
+
text: str
|
|
14
|
+
level: int = 0
|
mud/models/json_io.py
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import MISSING, asdict, fields, is_dataclass
|
|
5
|
+
from typing import Any, Type, TypeVar, get_args, get_origin, get_type_hints, cast
|
|
6
|
+
|
|
7
|
+
T = TypeVar("T")
|
|
8
|
+
JsonT = TypeVar("JsonT", bound="JsonDataclass")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _convert_value(annotation, value):
|
|
12
|
+
origin = get_origin(annotation)
|
|
13
|
+
if is_dataclass(annotation):
|
|
14
|
+
return dataclass_from_dict(annotation, value)
|
|
15
|
+
if origin is list:
|
|
16
|
+
(item_type,) = get_args(annotation)
|
|
17
|
+
return [_convert_value(item_type, v) for v in value]
|
|
18
|
+
if origin is dict:
|
|
19
|
+
key_type, val_type = get_args(annotation)
|
|
20
|
+
# assume keys are primitive; only convert values
|
|
21
|
+
return {k: _convert_value(val_type, v) for k, v in value.items()}
|
|
22
|
+
return value
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def dataclass_from_dict(cls: Type[T], data: dict) -> T:
|
|
26
|
+
"""Instantiate ``cls`` from ``data`` applying dataclass defaults."""
|
|
27
|
+
kwargs = {}
|
|
28
|
+
hints = get_type_hints(cls)
|
|
29
|
+
for f in fields(cast(Any, cls)):
|
|
30
|
+
ann = hints.get(f.name, f.type)
|
|
31
|
+
if f.name in data:
|
|
32
|
+
kwargs[f.name] = _convert_value(ann, data[f.name])
|
|
33
|
+
elif f.default is not MISSING:
|
|
34
|
+
kwargs[f.name] = f.default
|
|
35
|
+
elif f.default_factory is not MISSING: # type: ignore[attr-defined]
|
|
36
|
+
kwargs[f.name] = f.default_factory() # type: ignore[misc]
|
|
37
|
+
return cls(**kwargs) # type: ignore[arg-type]
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def dataclass_to_dict(obj: Any) -> dict:
|
|
41
|
+
"""Convert ``obj`` into a JSON-serializable ``dict``."""
|
|
42
|
+
return asdict(obj)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def load_dataclass(cls: Type[T], fp) -> T:
|
|
46
|
+
"""Load ``cls`` from a JSON file-like object."""
|
|
47
|
+
data = json.load(fp)
|
|
48
|
+
return dataclass_from_dict(cls, data)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def dump_dataclass(obj: Any, fp, **json_kwargs) -> None:
|
|
52
|
+
"""Dump dataclass instance ``obj`` to ``fp`` as JSON."""
|
|
53
|
+
json.dump(dataclass_to_dict(obj), fp, **json_kwargs)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class JsonDataclass:
|
|
57
|
+
"""Mixin adding ``to_dict``/``from_dict`` helpers to dataclasses."""
|
|
58
|
+
|
|
59
|
+
def to_dict(self) -> dict:
|
|
60
|
+
return dataclass_to_dict(self)
|
|
61
|
+
|
|
62
|
+
@classmethod
|
|
63
|
+
def from_dict(cls: Type[JsonT], data: dict) -> JsonT:
|
|
64
|
+
return dataclass_from_dict(cls, data)
|
mud/models/mob.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import List, Optional, Tuple
|
|
4
|
+
|
|
5
|
+
@dataclass
|
|
6
|
+
class MobProgram:
|
|
7
|
+
"""Representation of MPROG_LIST"""
|
|
8
|
+
trig_type: int
|
|
9
|
+
trig_phrase: Optional[str] = None
|
|
10
|
+
vnum: int = 0
|
|
11
|
+
code: Optional[str] = None
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class MobIndex:
|
|
15
|
+
"""Python representation of MOB_INDEX_DATA"""
|
|
16
|
+
vnum: int
|
|
17
|
+
player_name: Optional[str] = None
|
|
18
|
+
short_descr: Optional[str] = None
|
|
19
|
+
long_descr: Optional[str] = None
|
|
20
|
+
description: Optional[str] = None
|
|
21
|
+
race: Optional[str] = None
|
|
22
|
+
act_flags: str = ''
|
|
23
|
+
affected_by: str = ''
|
|
24
|
+
alignment: int = 0
|
|
25
|
+
group: int = 0
|
|
26
|
+
level: int = 1
|
|
27
|
+
thac0: int = 20
|
|
28
|
+
ac: str = '1d1+0'
|
|
29
|
+
hit_dice: str = '1d1+0'
|
|
30
|
+
mana_dice: str = '1d1+0'
|
|
31
|
+
damage_dice: str = '1d4+0'
|
|
32
|
+
damage_type: str = 'beating'
|
|
33
|
+
ac_pierce: int = 0
|
|
34
|
+
ac_bash: int = 0
|
|
35
|
+
ac_slash: int = 0
|
|
36
|
+
ac_exotic: int = 0
|
|
37
|
+
offensive: str = ''
|
|
38
|
+
immune: str = ''
|
|
39
|
+
resist: str = ''
|
|
40
|
+
vuln: str = ''
|
|
41
|
+
start_pos: str = 'standing'
|
|
42
|
+
default_pos: str = 'standing'
|
|
43
|
+
sex: str = 'neutral'
|
|
44
|
+
wealth: int = 0
|
|
45
|
+
form: str = '0'
|
|
46
|
+
parts: str = '0'
|
|
47
|
+
size: str = 'medium'
|
|
48
|
+
material: str = '0'
|
|
49
|
+
spec_fun: Optional[str] = None
|
|
50
|
+
pShop: Optional[object] = None
|
|
51
|
+
mprogs: List[MobProgram] = field(default_factory=list)
|
|
52
|
+
area: Optional['Area'] = None
|
|
53
|
+
new_format: bool = False
|
|
54
|
+
count: int = 0
|
|
55
|
+
killed: int = 0
|
|
56
|
+
# Legacy compatibility fields
|
|
57
|
+
act: int = 0
|
|
58
|
+
hitroll: int = 0
|
|
59
|
+
hit: Tuple[int, int, int] = (0, 0, 0)
|
|
60
|
+
mana: Tuple[int, int, int] = (0, 0, 0)
|
|
61
|
+
damage: Tuple[int, int, int] = (0, 0, 0)
|
|
62
|
+
dam_type: int = 0
|
|
63
|
+
off_flags: int = 0
|
|
64
|
+
imm_flags: int = 0
|
|
65
|
+
res_flags: int = 0
|
|
66
|
+
vuln_flags: int = 0
|
|
67
|
+
start_pos: int = 0
|
|
68
|
+
default_pos: int = 0
|
|
69
|
+
sex: int = 0
|
|
70
|
+
race: int = 0
|
|
71
|
+
wealth: int = 0
|
|
72
|
+
form: int = 0
|
|
73
|
+
parts: int = 0
|
|
74
|
+
size: int = 0
|
|
75
|
+
material: Optional[str] = None
|
|
76
|
+
mprog_flags: int = 0
|
|
77
|
+
|
|
78
|
+
def __repr__(self) -> str:
|
|
79
|
+
return f"<MobIndex vnum={self.vnum} name={self.short_descr!r}>"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
mob_registry: dict[int, MobIndex] = {}
|
mud/models/note.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from .note_json import NoteJson
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Note:
|
|
10
|
+
"""Runtime representation of a message board note."""
|
|
11
|
+
|
|
12
|
+
sender: str
|
|
13
|
+
to: str
|
|
14
|
+
subject: str
|
|
15
|
+
text: str
|
|
16
|
+
timestamp: float
|
|
17
|
+
|
|
18
|
+
def to_json(self) -> NoteJson:
|
|
19
|
+
return NoteJson(
|
|
20
|
+
sender=self.sender,
|
|
21
|
+
to=self.to,
|
|
22
|
+
subject=self.subject,
|
|
23
|
+
text=self.text,
|
|
24
|
+
timestamp=self.timestamp,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_json(cls, data: NoteJson) -> "Note":
|
|
29
|
+
return cls(**data.to_dict())
|
mud/models/note_json.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
from .json_io import JsonDataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class NoteJson(JsonDataclass):
|
|
10
|
+
"""Schema-aligned representation of a message board note."""
|
|
11
|
+
|
|
12
|
+
sender: str
|
|
13
|
+
to: str
|
|
14
|
+
subject: str
|
|
15
|
+
text: str
|
|
16
|
+
timestamp: float
|
mud/models/obj.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from .room import ExtraDescr, Room
|
|
3
|
+
from .character import Character
|
|
4
|
+
from dataclasses import dataclass, field
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class Affect:
|
|
9
|
+
"""Representation of AFFECT_DATA"""
|
|
10
|
+
where: int
|
|
11
|
+
type: int
|
|
12
|
+
level: int
|
|
13
|
+
duration: int
|
|
14
|
+
location: int
|
|
15
|
+
modifier: int
|
|
16
|
+
bitvector: int
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ObjIndex:
|
|
20
|
+
"""Python representation of OBJ_INDEX_DATA"""
|
|
21
|
+
vnum: int
|
|
22
|
+
name: Optional[str] = None
|
|
23
|
+
short_descr: Optional[str] = None
|
|
24
|
+
description: Optional[str] = None
|
|
25
|
+
material: Optional[str] = None
|
|
26
|
+
item_type: str = 'trash'
|
|
27
|
+
extra_flags: int = 0
|
|
28
|
+
wear_flags: str = ''
|
|
29
|
+
level: int = 0
|
|
30
|
+
condition: str = 'P'
|
|
31
|
+
count: int = 0
|
|
32
|
+
weight: int = 0
|
|
33
|
+
cost: int = 0
|
|
34
|
+
value: List[int] = field(default_factory=lambda: [0] * 5)
|
|
35
|
+
affects: List[dict] = field(default_factory=list) # {'location': int, 'modifier': int}
|
|
36
|
+
extra_descr: List[dict] = field(default_factory=list) # {'keyword': str, 'description': str}
|
|
37
|
+
area: Optional['Area'] = None
|
|
38
|
+
new_format: bool = False
|
|
39
|
+
reset_num: int = 0
|
|
40
|
+
next: Optional['ObjIndex'] = None
|
|
41
|
+
# Legacy compatibility
|
|
42
|
+
affected: List[Affect] = field(default_factory=list)
|
|
43
|
+
|
|
44
|
+
def __repr__(self) -> str:
|
|
45
|
+
return f"<ObjIndex vnum={self.vnum} name={self.short_descr!r}>"
|
|
46
|
+
|
|
47
|
+
obj_index_registry: dict[int, ObjIndex] = {}
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class ObjectData:
|
|
51
|
+
"""Python representation of OBJ_DATA"""
|
|
52
|
+
item_type: int
|
|
53
|
+
extra_flags: int = 0
|
|
54
|
+
wear_flags: int = 0
|
|
55
|
+
wear_loc: int = 0
|
|
56
|
+
weight: int = 0
|
|
57
|
+
cost: int = 0
|
|
58
|
+
level: int = 0
|
|
59
|
+
condition: int = 0
|
|
60
|
+
timer: int = 0
|
|
61
|
+
value: List[int] = field(default_factory=lambda: [0] * 5)
|
|
62
|
+
owner: Optional[str] = None
|
|
63
|
+
name: Optional[str] = None
|
|
64
|
+
short_descr: Optional[str] = None
|
|
65
|
+
description: Optional[str] = None
|
|
66
|
+
material: Optional[str] = None
|
|
67
|
+
carried_by: Optional['Character'] = None
|
|
68
|
+
in_obj: Optional['ObjectData'] = None
|
|
69
|
+
contains: List['ObjectData'] = field(default_factory=list)
|
|
70
|
+
extra_descr: List['ExtraDescr'] = field(default_factory=list)
|
|
71
|
+
affected: List[Affect] = field(default_factory=list)
|
|
72
|
+
pIndexData: Optional[ObjIndex] = None
|
|
73
|
+
in_room: Optional['Room'] = None
|
|
74
|
+
enchanted: bool = False
|
|
75
|
+
next_content: Optional['ObjectData'] = None
|
|
76
|
+
next: Optional['ObjectData'] = None
|
|
77
|
+
|
|
78
|
+
def __repr__(self) -> str:
|
|
79
|
+
return f"<ObjectData type={self.item_type} name={self.short_descr!r}>"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
object_registry: list[ObjectData] = []
|
mud/models/object.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import Optional, List, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from .room import Room
|
|
7
|
+
|
|
8
|
+
from .obj import ObjIndex
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class Object:
|
|
13
|
+
"""Instance of an object tied to a prototype."""
|
|
14
|
+
instance_id: Optional[int]
|
|
15
|
+
prototype: ObjIndex
|
|
16
|
+
location: Optional['Room'] = None
|
|
17
|
+
contained_items: List['Object'] = field(default_factory=list)
|
|
18
|
+
level: int = 0
|
|
19
|
+
# Instance values — copy of prototype.value for runtime mutations (e.g., locks/charges)
|
|
20
|
+
value: List[int] = field(default_factory=lambda: [0, 0, 0, 0, 0])
|
|
21
|
+
|
|
22
|
+
@property
|
|
23
|
+
def name(self) -> Optional[str]:
|
|
24
|
+
return self.prototype.name
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def short_descr(self) -> Optional[str]:
|
|
28
|
+
return getattr(self.prototype, "short_descr", None)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
|
|
6
|
+
from .json_io import JsonDataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class AffectJson(JsonDataclass):
|
|
11
|
+
"""Per-object affect modifier."""
|
|
12
|
+
location: str
|
|
13
|
+
modifier: int
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass
|
|
17
|
+
class ExtraDescriptionJson(JsonDataclass):
|
|
18
|
+
"""Extra description block for objects."""
|
|
19
|
+
keyword: str
|
|
20
|
+
description: str
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class ObjectJson(JsonDataclass):
|
|
25
|
+
"""Object record matching ``schemas/object.schema.json``."""
|
|
26
|
+
id: int
|
|
27
|
+
name: str
|
|
28
|
+
description: str
|
|
29
|
+
item_type: str
|
|
30
|
+
values: List[int]
|
|
31
|
+
weight: int
|
|
32
|
+
cost: int
|
|
33
|
+
short_description: Optional[str] = None
|
|
34
|
+
flags: List[str] = field(default_factory=list)
|
|
35
|
+
wear_flags: List[str] = field(default_factory=list)
|
|
36
|
+
level: int = 0
|
|
37
|
+
condition: int = 0
|
|
38
|
+
material: str = ""
|
|
39
|
+
affects: List[AffectJson] = field(default_factory=list)
|
|
40
|
+
extra_descriptions: List[ExtraDescriptionJson] = field(default_factory=list)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
from .json_io import JsonDataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class PlayerJson(JsonDataclass):
|
|
11
|
+
"""Player record matching ``schemas/player.schema.json``."""
|
|
12
|
+
|
|
13
|
+
name: str
|
|
14
|
+
level: int
|
|
15
|
+
hit: int
|
|
16
|
+
max_hit: int
|
|
17
|
+
mana: int
|
|
18
|
+
max_mana: int
|
|
19
|
+
move: int
|
|
20
|
+
max_move: int
|
|
21
|
+
gold: int
|
|
22
|
+
silver: int
|
|
23
|
+
exp: int
|
|
24
|
+
position: int
|
|
25
|
+
room_vnum: Optional[int]
|
|
26
|
+
inventory: List[int] = field(default_factory=list)
|
|
27
|
+
equipment: Dict[str, int] = field(default_factory=dict)
|
|
28
|
+
plr_flags: int = 0
|
|
29
|
+
comm_flags: int = 0
|
mud/models/room.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
|
+
from typing import List, Optional, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
if TYPE_CHECKING:
|
|
6
|
+
from mud.models.object import Object
|
|
7
|
+
from mud.spawning.templates import MobInstance
|
|
8
|
+
from mud.models.area import Area
|
|
9
|
+
from mud.models.character import Character
|
|
10
|
+
|
|
11
|
+
from .constants import Direction
|
|
12
|
+
from .room_json import ResetJson
|
|
13
|
+
|
|
14
|
+
@dataclass
|
|
15
|
+
class ExtraDescr:
|
|
16
|
+
"""Python representation of EXTRA_DESCR_DATA"""
|
|
17
|
+
keyword: Optional[str] = None
|
|
18
|
+
description: Optional[str] = None
|
|
19
|
+
|
|
20
|
+
@dataclass
|
|
21
|
+
class Exit:
|
|
22
|
+
"""Representation of EXIT_DATA"""
|
|
23
|
+
to_room: Optional['Room'] = None
|
|
24
|
+
vnum: Optional[int] = None
|
|
25
|
+
exit_info: int = 0
|
|
26
|
+
key: int = 0
|
|
27
|
+
keyword: Optional[str] = None
|
|
28
|
+
description: Optional[str] = None
|
|
29
|
+
flags: str = '0' # String representation of exit flags
|
|
30
|
+
rs_flags: int = 0
|
|
31
|
+
orig_door: int = 0
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class Room:
|
|
35
|
+
"""Runtime room container built from area files."""
|
|
36
|
+
vnum: int
|
|
37
|
+
name: Optional[str] = None
|
|
38
|
+
description: Optional[str] = None
|
|
39
|
+
owner: Optional[str] = None
|
|
40
|
+
area: Optional['Area'] = None
|
|
41
|
+
room_flags: int = 0
|
|
42
|
+
light: int = 0
|
|
43
|
+
sector_type: int = 0
|
|
44
|
+
heal_rate: int = 0
|
|
45
|
+
mana_rate: int = 0
|
|
46
|
+
clan: int = 0
|
|
47
|
+
exits: List[Optional[Exit]] = field(default_factory=lambda: [None] * len(Direction))
|
|
48
|
+
extra_descr: List[ExtraDescr] = field(default_factory=list)
|
|
49
|
+
resets: List[ResetJson] = field(default_factory=list)
|
|
50
|
+
people: List['Character'] = field(default_factory=list)
|
|
51
|
+
contents: List['Object'] = field(default_factory=list)
|
|
52
|
+
next: Optional['Room'] = None
|
|
53
|
+
|
|
54
|
+
def __repr__(self) -> str:
|
|
55
|
+
return f"<Room vnum={self.vnum} name={self.name!r}>"
|
|
56
|
+
|
|
57
|
+
def add_character(self, char: 'Character') -> None:
|
|
58
|
+
if char not in self.people:
|
|
59
|
+
self.people.append(char)
|
|
60
|
+
char.room = self
|
|
61
|
+
|
|
62
|
+
def remove_character(self, char: 'Character') -> None:
|
|
63
|
+
if char in self.people:
|
|
64
|
+
self.people.remove(char)
|
|
65
|
+
|
|
66
|
+
def add_object(self, obj: 'Object') -> None:
|
|
67
|
+
if obj not in self.contents:
|
|
68
|
+
self.contents.append(obj)
|
|
69
|
+
if hasattr(obj, "location"):
|
|
70
|
+
obj.location = self
|
|
71
|
+
|
|
72
|
+
def add_mob(self, mob: 'MobInstance') -> None:
|
|
73
|
+
if mob not in self.people:
|
|
74
|
+
self.people.append(mob)
|
|
75
|
+
mob.room = self
|
|
76
|
+
|
|
77
|
+
def broadcast(self, message: str, exclude: Optional['Character'] = None) -> None:
|
|
78
|
+
for char in self.people:
|
|
79
|
+
if char is exclude:
|
|
80
|
+
continue
|
|
81
|
+
if hasattr(char, 'messages'):
|
|
82
|
+
char.messages.append(message)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
room_registry: dict[int, Room] = {}
|
|
86
|
+
|
mud/models/room_json.py
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Dict, List, Optional
|
|
5
|
+
|
|
6
|
+
from .json_io import JsonDataclass
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class ExitJson(JsonDataclass):
|
|
11
|
+
"""Exit specification for JSON rooms."""
|
|
12
|
+
to_room: int
|
|
13
|
+
description: Optional[str] = None
|
|
14
|
+
keyword: Optional[str] = None
|
|
15
|
+
flags: List[str] = field(default_factory=list)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@dataclass
|
|
19
|
+
class ExtraDescriptionJson(JsonDataclass):
|
|
20
|
+
"""Extra description block for JSON rooms."""
|
|
21
|
+
keyword: str
|
|
22
|
+
description: str
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class ResetJson(JsonDataclass):
|
|
27
|
+
"""Reset command affecting a room."""
|
|
28
|
+
command: str
|
|
29
|
+
arg1: Optional[int] = None
|
|
30
|
+
arg2: Optional[int] = None
|
|
31
|
+
arg3: Optional[int] = None
|
|
32
|
+
arg4: Optional[int] = None
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass
|
|
36
|
+
class RoomJson(JsonDataclass):
|
|
37
|
+
"""Room record matching ``schemas/room.schema.json``."""
|
|
38
|
+
id: int
|
|
39
|
+
name: str
|
|
40
|
+
description: str
|
|
41
|
+
sector_type: str
|
|
42
|
+
area: int
|
|
43
|
+
flags: List[str] = field(default_factory=list)
|
|
44
|
+
exits: Dict[str, ExitJson] = field(default_factory=dict)
|
|
45
|
+
extra_descriptions: List[ExtraDescriptionJson] = field(default_factory=list)
|
|
46
|
+
resets: List[ResetJson] = field(default_factory=list)
|
mud/models/shop.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from .shop_json import ShopJson
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class Shop:
|
|
10
|
+
"""Runtime representation of a shop."""
|
|
11
|
+
|
|
12
|
+
keeper: int
|
|
13
|
+
buy_types: list[str] = field(default_factory=list)
|
|
14
|
+
profit_buy: int = 100
|
|
15
|
+
profit_sell: int = 100
|
|
16
|
+
open_hour: int = 0
|
|
17
|
+
close_hour: int = 23
|
|
18
|
+
|
|
19
|
+
@classmethod
|
|
20
|
+
def from_json(cls, data: ShopJson) -> "Shop":
|
|
21
|
+
return cls(**data.to_dict())
|
mud/models/shop_json.py
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from .json_io import JsonDataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class ShopJson(JsonDataclass):
|
|
10
|
+
"""Shop record matching ``schemas/shop.schema.json``."""
|
|
11
|
+
|
|
12
|
+
keeper: int
|
|
13
|
+
buy_types: list[str] = field(default_factory=list)
|
|
14
|
+
profit_buy: int = 100
|
|
15
|
+
profit_sell: int = 100
|
|
16
|
+
open_hour: int = 0
|
|
17
|
+
close_hour: int = 23
|
mud/models/skill.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Dict
|
|
5
|
+
|
|
6
|
+
from .skill_json import SkillJson
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class Skill:
|
|
11
|
+
"""Runtime representation of a skill or spell."""
|
|
12
|
+
|
|
13
|
+
name: str
|
|
14
|
+
type: str
|
|
15
|
+
function: str
|
|
16
|
+
target: str = "victim"
|
|
17
|
+
mana_cost: int = 0
|
|
18
|
+
lag: int = 0
|
|
19
|
+
cooldown: int = 0
|
|
20
|
+
failure_rate: float = 0.0
|
|
21
|
+
messages: Dict[str, str] = field(default_factory=dict)
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_json(cls, data: SkillJson) -> "Skill":
|
|
25
|
+
return cls(**data.to_dict())
|
mud/models/skill_json.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
|
|
5
|
+
from .json_io import JsonDataclass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dataclass
|
|
9
|
+
class SkillJson(JsonDataclass):
|
|
10
|
+
"""Schema-aligned representation of a skill or spell."""
|
|
11
|
+
|
|
12
|
+
name: str
|
|
13
|
+
type: str
|
|
14
|
+
function: str
|
|
15
|
+
target: str = "victim"
|
|
16
|
+
mana_cost: int = 0
|
|
17
|
+
lag: int = 0
|
|
18
|
+
cooldown: int = 0
|
|
19
|
+
failure_rate: float = 0.0
|
|
20
|
+
messages: dict[str, str] = field(default_factory=dict)
|