rom24-quickmud-python 2.9.19__py3-none-any.whl → 2.9.21__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.
@@ -259,16 +259,45 @@ def do_group(char: Character, args: str) -> str:
259
259
  if char_affected & AffectFlag.CHARM:
260
260
  return "You like your master too much to leave!"
261
261
 
262
- # Already in group - remove
262
+ leader_name = _display_name(char)
263
+ victim_name_str = _display_name(victim)
264
+
265
+ # Already in group - remove (ROM src/act_comm.c:1838-1847)
263
266
  if is_same_group(victim, char) and char is not victim:
264
267
  victim.leader = None
265
- victim_name = getattr(victim, "short_descr", None) or getattr(victim, "name", "them")
266
- return f"You remove {victim_name} from your group."
267
-
268
- # Add to group
268
+ # TO_VICT: "$n removes you from $s group."
269
+ victim_messages = getattr(victim, "messages", None)
270
+ if isinstance(victim_messages, list):
271
+ victim_messages.append(f"{leader_name} removes you from {leader_name}'s group.")
272
+ # TO_NOTVICT: "$n removes $N from $s group."
273
+ room = getattr(char, "room", None)
274
+ if room is not None:
275
+ notvict_msg = f"{leader_name} removes {victim_name_str} from {leader_name}'s group."
276
+ for occupant in list(getattr(room, "people", []) or []):
277
+ if occupant is char or occupant is victim:
278
+ continue
279
+ occ_messages = getattr(occupant, "messages", None)
280
+ if isinstance(occ_messages, list):
281
+ occ_messages.append(notvict_msg)
282
+ return f"You remove {victim_name_str} from your group."
283
+
284
+ # Add to group (ROM src/act_comm.c:1850-1854)
269
285
  victim.leader = char
270
- victim_name = getattr(victim, "short_descr", None) or getattr(victim, "name", "someone")
271
- return f"{victim_name} joins your group."
286
+ # TO_VICT: "You join $n's group."
287
+ victim_messages = getattr(victim, "messages", None)
288
+ if isinstance(victim_messages, list):
289
+ victim_messages.append(f"You join {leader_name}'s group.")
290
+ # TO_NOTVICT: "$N joins $n's group."
291
+ room = getattr(char, "room", None)
292
+ if room is not None:
293
+ notvict_msg = f"{victim_name_str} joins {leader_name}'s group."
294
+ for occupant in list(getattr(room, "people", []) or []):
295
+ if occupant is char or occupant is victim:
296
+ continue
297
+ occ_messages = getattr(occupant, "messages", None)
298
+ if isinstance(occ_messages, list):
299
+ occ_messages.append(notvict_msg)
300
+ return f"{victim_name_str} joins your group."
272
301
 
273
302
 
274
303
  def do_gtell(char: Character, args: str) -> str:
mud/models/object.py CHANGED
@@ -166,3 +166,41 @@ def create_object(prototype: ObjIndex, *, instance_id: int | None = None) -> Obj
166
166
  obj = Object(instance_id=instance_id, prototype=prototype)
167
167
  object_registry.append(obj)
168
168
  return obj
169
+
170
+
171
+ def recursive_clone(obj: Object, clone_to: Object | None = None) -> Object:
172
+ """Deep-clone *obj* including container contents.
173
+
174
+ ROM parity: src/act_wiz.c:recursive_clone (line 2320). Used by the
175
+ immortal ``clone`` command and OLC paths.
176
+ """
177
+ from mud.models.obj import ObjIndex
178
+
179
+ if not obj.prototype:
180
+ proto = ObjIndex(
181
+ vnum=obj.vnum,
182
+ name=obj.name,
183
+ short_descr=obj.short_descr,
184
+ long_descr=obj.long_descr,
185
+ description=obj.description,
186
+ item_type=obj.item_type,
187
+ extra_flags=obj.extra_flags,
188
+ wear_flags=obj.wear_flags,
189
+ value=obj.value.copy() if obj.value else [0, 0, 0, 0, 0],
190
+ weight=obj.weight,
191
+ cost=obj.cost,
192
+ level=obj.level,
193
+ )
194
+ else:
195
+ proto = obj.prototype
196
+
197
+ new_obj = create_object(proto)
198
+
199
+ for content in obj.contained_items:
200
+ recursive_clone(content, new_obj)
201
+
202
+ if clone_to:
203
+ clone_to.contained_items.append(new_obj)
204
+ new_obj.location = None
205
+
206
+ return new_obj
mud/world/look.py CHANGED
@@ -53,7 +53,7 @@ def look(char: Character, args: str = "") -> str:
53
53
  return "You can't see anything, you're sleeping!"
54
54
 
55
55
  # Check blind - ROM src/act_info.c lines 1065-1066
56
- from mud.rom_api import check_blind
56
+ from mud.world.vision import check_blind
57
57
 
58
58
  if not check_blind(char):
59
59
  return "You can't see a thing!"
mud/world/vision.py CHANGED
@@ -371,3 +371,22 @@ def describe_character(observer: Character, target: Character | None) -> str:
371
371
  return " ".join(prefixes) + " " + base_name
372
372
 
373
373
  return base_name
374
+
375
+
376
+ def check_blind(char: Character) -> bool:
377
+ """Return True when *char* is not blinded, False otherwise.
378
+
379
+ ROM parity: src/act_info.c:check_blind (line 542).
380
+ """
381
+ checker = getattr(char, "has_affect", None)
382
+ if callable(checker):
383
+ try:
384
+ return not bool(checker(AffectFlag.BLIND))
385
+ except Exception:
386
+ pass
387
+
388
+ affected = getattr(char, "affected_by", 0)
389
+ try:
390
+ return not bool(int(affected) & int(AffectFlag.BLIND))
391
+ except Exception:
392
+ return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rom24-quickmud-python
3
- Version: 2.9.19
3
+ Version: 2.9.21
4
4
  Summary: A modern Python port of the ROM 2.4b6 MUD engine with full telnet server and JSON world loading
5
5
  Author-email: Mark Jedrzejczyk <mark.jedrzejczyk@gmail.com>
6
6
  Maintainer-email: Mark Jedrzejczyk <mark.jedrzejczyk@gmail.com>
@@ -11,7 +11,6 @@ mud/mob_cmds.py,sha256=Hv7tFhABraQLRbQihHOHTDE4qgE0GSuue1_RQkchQW4,46158
11
11
  mud/mobprog.py,sha256=TZiv4ZErFAlcO1TWaJryzZ5kwTZFe5DSqKVlo6qJcTc,59173
12
12
  mud/notes.py,sha256=mJM_f1lQ-Y1us7MHzHkgfozYKQCBm84FKRjmKpgoiOE,11501
13
13
  mud/registry.py,sha256=s8tGVKLZUU6-5c7HtBqhHQWLVxzFM4A9bpJ8avGt_0I,306
14
- mud/rom_api.py,sha256=4XIQZvWt6oNLiUBGr-NShCQ3Ev9nSEMGNh01VPowagA,17256
15
14
  mud/server.py,sha256=fv6mprd4h9CejTt8kOFkt6RA-NdzTwOd24d_3p9aOKY,219
16
15
  mud/spec_funs.py,sha256=D4x9el8po1FYDY8ZbPwDkJ4ujtIq7fEW1lCvJW8POdk,47536
17
16
  mud/time.py,sha256=eVMXzVoi9w7gGE7bN1FVYjCwSwBydSpkkVtptV4qTtw,1324
@@ -59,7 +58,7 @@ mud/commands/doors.py,sha256=KWMQPVJHs8-xPFE08kStOOU9x5ugN5sEFuo7nlQL2Z8,19777
59
58
  mud/commands/equipment.py,sha256=BXUJhe_volohdgUKpugV8Wfcn-pHXG6ooaKeF6LmcI4,22882
60
59
  mud/commands/feedback.py,sha256=qEmUlVy1KC6ludpAREdqvf8gpa8jmgN4AMLor0EoO7E,2472
61
60
  mud/commands/give.py,sha256=BcZjqFm1WqhoRi9qZJ8G9zRu_buXptwg9Y7_oSNnFVE,8787
62
- mud/commands/group_commands.py,sha256=_9KroYmWxm3CfvhJj5iFEw1szXS-UlGIe8YiOm3IVU8,18627
61
+ mud/commands/group_commands.py,sha256=Cz3LNTCccR4ghpyE5QORDlZBwpzkli93uueF3zZBoHk,20077
63
62
  mud/commands/healer.py,sha256=noZ3t97C_0j1GEJd8nUNYYv4clHxuD4dvFSR3c1gfUA,7576
64
63
  mud/commands/help.py,sha256=GfQWy6MyFtDc-mW1dM7pPN1SFVsWtIGno8uR4dRQYjg,11124
65
64
  mud/commands/imc.py,sha256=v1lPP2xDjQjkk7negwjCXJtcRPQkBEIGWmpPKf1XPzU,12204
@@ -147,7 +146,7 @@ mud/models/mob.py,sha256=d2JGyNh74c-FQYmFQPXN9M9sb3valppaDRLUe49cMcc,3830
147
146
  mud/models/note.py,sha256=stKuDsBJ5UQHngPVRbgDH4me_6RtUgjRczC2X3jbhgI,653
148
147
  mud/models/note_json.py,sha256=BuYWIGyZFevoObHGknfMOxjpL0laP7G070wNPZLccXU,320
149
148
  mud/models/obj.py,sha256=VNVKGLR9uUFOlGnLeFjRaeH4sAXE_gtyJV43lz4UVuY,2141
150
- mud/models/object.py,sha256=0dtGzbErRPBARyR0IHtlyVMttUAkTzOU5EzGcbLzSQ0,6540
149
+ mud/models/object.py,sha256=9KLQ8xL5cA9yC7uyrf5d8fH_ugfWVqbDwXtzSfzHqKw,7628
151
150
  mud/models/object_json.py,sha256=v1_FnQnvkGBM1lnXPWQARfDQrs20C5mZDhCaLYgNiZs,960
152
151
  mud/models/player_json.py,sha256=YQerAs3vxyAo7wr3orCXCC-pM_QWiwbz3aQ9RMzWW-Q,1249
153
152
  mud/models/races.py,sha256=U-77PyNogpyLEhdHrwA8Yll3ekBBTYKYfj-l26Catm4,17138
@@ -210,15 +209,15 @@ mud/utils/text.py,sha256=_HWbi7RAneH8EUZTkx6yKn8ngEpCwKgW_wcTlNJihE0,4357
210
209
  mud/world/__init__.py,sha256=HDEHtULHu1OWjOa3xglmhquW8L6NkJTWzLEURJ4BQjk,263
211
210
  mud/world/char_find.py,sha256=WdzbnOhydQfKIhhtDFQ8IhcYGT-HlwXrR7pjRFjtNFk,3283
212
211
  mud/world/linking.py,sha256=mxEvgqA9Y6sDGXxN46aauU-jBhx4dOUcbgq64fIVz8g,1169
213
- mud/world/look.py,sha256=XSsTsmAxawVz17A_28eIwosUGNkWE8T7u8hGdo57mCs,13365
212
+ mud/world/look.py,sha256=Hocwuzi8sDCBcVaklj1WtWnAs5zRzGGkqC5B-3JCZf0,13370
214
213
  mud/world/movement.py,sha256=YdeVZXM_h0RDNyQGK7zuz_2Ld5h5m7IDKpgbRCGJK20,23231
215
214
  mud/world/obj_find.py,sha256=tgnUkbFjnCl586Lzl6yRzCmllZSNEfQpQlrxCMVcUGU,5295
216
215
  mud/world/time_persistence.py,sha256=K4uhRpu08IDHY5uReBYTvw4BHuqsSxWvbv-h1VsPvf8,1663
217
- mud/world/vision.py,sha256=NRk3cvrGyyldU4W98qAVlYZp9wL-IUE1dTgk6DpM-NA,11609
216
+ mud/world/vision.py,sha256=EOw_HQdVXBCvry0lReA0ZhxSt0VL59ME-ua92oNYTAc,12128
218
217
  mud/world/world_state.py,sha256=3KpiDP6v24sZDn9-g44UypXpegzgRShHo1XvektJzdU,8810
219
- rom24_quickmud_python-2.9.19.dist-info/licenses/LICENSE,sha256=anQ2j9As6sIC8tZgQCXbo0-09JDH9vPiqhA9djnOvkY,1078
220
- rom24_quickmud_python-2.9.19.dist-info/METADATA,sha256=NSFn4LIyR0pjXXeGRQ4L6mSzo2Ym-I3BC3z3tRS0n98,15671
221
- rom24_quickmud_python-2.9.19.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
222
- rom24_quickmud_python-2.9.19.dist-info/entry_points.txt,sha256=VFru08UQTXZA_CkK-NBjJmWHyEX5a3864fQHjhaojbw,41
223
- rom24_quickmud_python-2.9.19.dist-info/top_level.txt,sha256=Fk1WPmabIIjp7_iZXLYpbAVqiq7lG7TeAHt30AsOKtQ,4
224
- rom24_quickmud_python-2.9.19.dist-info/RECORD,,
218
+ rom24_quickmud_python-2.9.21.dist-info/licenses/LICENSE,sha256=anQ2j9As6sIC8tZgQCXbo0-09JDH9vPiqhA9djnOvkY,1078
219
+ rom24_quickmud_python-2.9.21.dist-info/METADATA,sha256=C-Kmz3VPkEIQTWAs2rX6uMbGAA4U-4Gm9C-l8gkjRxk,15671
220
+ rom24_quickmud_python-2.9.21.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
221
+ rom24_quickmud_python-2.9.21.dist-info/entry_points.txt,sha256=VFru08UQTXZA_CkK-NBjJmWHyEX5a3864fQHjhaojbw,41
222
+ rom24_quickmud_python-2.9.21.dist-info/top_level.txt,sha256=Fk1WPmabIIjp7_iZXLYpbAVqiq7lG7TeAHt30AsOKtQ,4
223
+ rom24_quickmud_python-2.9.21.dist-info/RECORD,,
mud/rom_api.py DELETED
@@ -1,690 +0,0 @@
1
- """
2
- ROM 2.4 Parity API - Public wrapper functions for ROM C compatibility.
3
-
4
- This module provides ROM C-compatible public API functions that wrap existing
5
- Python implementations. These wrappers use ROM C naming conventions for
6
- compatibility with external tools and documentation.
7
-
8
- ROM Reference: src/board.c, src/olc_act.c, src/handler.c
9
- """
10
-
11
- from __future__ import annotations
12
-
13
- from typing import TYPE_CHECKING
14
-
15
- if TYPE_CHECKING:
16
- from mud.models.board import Board
17
- from mud.models.character import Character
18
- from mud.models.note import Note
19
- from mud.models.object import Object
20
-
21
-
22
- # =============================================================================
23
- # Board System Public API (src/board.c)
24
- # =============================================================================
25
-
26
-
27
- def board_lookup(name: str) -> Board | None:
28
- """Find board by name.
29
-
30
- ROM parity: src/board.c:board_lookup (line 201)
31
-
32
- Args:
33
- name: Board name to search for (case-insensitive)
34
-
35
- Returns:
36
- Board object if found, None otherwise
37
- """
38
- from mud.notes import find_board
39
-
40
- return find_board(name)
41
-
42
-
43
- def board_number(board_name: str) -> Board | None:
44
- """Get board by name (alias for board_lookup).
45
-
46
- ROM parity: src/board.c:board_number (line 189)
47
-
48
- Note: ROM C used numeric board IDs. Python uses names directly,
49
- so this is an alias for board_lookup for API compatibility.
50
-
51
- Args:
52
- board_name: Board name to retrieve
53
-
54
- Returns:
55
- Board object if found, None otherwise
56
- """
57
- from mud.notes import find_board
58
-
59
- return find_board(board_name)
60
-
61
-
62
- def is_note_to(char: Character, note: Note) -> bool:
63
- """Check if character can read a note.
64
-
65
- ROM parity: src/board.c:is_note_to (line 408)
66
-
67
- Checks if note is addressed to character based on:
68
- - Note recipient list (to_list)
69
- - Character name match
70
- - "all" recipient
71
-
72
- Args:
73
- char: Character to check visibility for
74
- note: Note to check
75
-
76
- Returns:
77
- True if character can read note, False otherwise
78
- """
79
- from mud.commands.notes import _is_note_visible_to
80
-
81
- return _is_note_visible_to(char, note)
82
-
83
-
84
- def note_from(note: Note) -> str:
85
- """Get note sender name.
86
-
87
- ROM parity: src/board.c (note->sender field access pattern)
88
-
89
- Args:
90
- note: Note to get sender from
91
-
92
- Returns:
93
- Sender name string
94
- """
95
- return note.sender
96
-
97
-
98
- # =============================================================================
99
- # Board Commands Public API (src/board.c)
100
- # =============================================================================
101
-
102
-
103
- def do_ncatchup(char: Character, args: str = "") -> str:
104
- """Mark all notes on current board as read.
105
-
106
- ROM parity: src/board.c:do_ncatchup (line 690)
107
-
108
- Args:
109
- char: Character executing command
110
- args: Command arguments (unused)
111
-
112
- Returns:
113
- Command result message
114
- """
115
- from mud.commands.notes import do_note
116
-
117
- return do_note(char, "catchup")
118
-
119
-
120
- def do_nremove(char: Character, args: str) -> str:
121
- """Remove a note from the board.
122
-
123
- ROM parity: src/board.c:do_nremove (line 615)
124
-
125
- Args:
126
- char: Character executing command
127
- args: Note number to remove
128
-
129
- Returns:
130
- Command result message
131
- """
132
- from mud.commands.notes import do_note
133
-
134
- return do_note(char, f"remove {args}")
135
-
136
-
137
- def do_nwrite(char: Character, args: str = "") -> str:
138
- """Start writing a new note.
139
-
140
- ROM parity: src/board.c:do_nwrite (line 467)
141
-
142
- Initiates note composition. Character can then use:
143
- - note to <recipient>
144
- - note subject <text>
145
- - note text (enters string editor)
146
- - note send
147
-
148
- Args:
149
- char: Character executing command
150
- args: Command arguments (unused)
151
-
152
- Returns:
153
- Command result message
154
- """
155
- from mud.commands.notes import do_note
156
-
157
- return do_note(char, "write")
158
-
159
-
160
- def do_nlist(char: Character, args: str = "") -> str:
161
- """List notes on current board.
162
-
163
- ROM parity: src/board.c:do_nlist (line 648)
164
-
165
- Args:
166
- char: Character executing command
167
- args: Command arguments (unused)
168
-
169
- Returns:
170
- Formatted list of notes
171
- """
172
- from mud.commands.notes import do_note
173
-
174
- return do_note(char, "list")
175
-
176
-
177
- def do_nread(char: Character, args: str) -> str:
178
- """Read a note from the board.
179
-
180
- ROM parity: src/board.c:do_nread (line 563)
181
-
182
- Args:
183
- char: Character executing command
184
- args: Note number to read or empty for next unread
185
-
186
- Returns:
187
- Note content or error message
188
- """
189
- from mud.commands.notes import do_note
190
-
191
- if args.strip():
192
- return do_note(char, f"read {args}")
193
- else:
194
- return do_note(char, "read")
195
-
196
-
197
- # =============================================================================
198
- # OLC Helper Functions Public API (src/olc_act.c)
199
- # =============================================================================
200
-
201
-
202
- def show_obj_values(obj) -> str:
203
- """Display object value fields formatted for OLC.
204
-
205
- ROM parity: src/olc_act.c:show_obj_values (line 2210)
206
-
207
- Shows v0-v4 value fields with descriptions based on item_type.
208
-
209
- Args:
210
- obj: Object to display values for
211
-
212
- Returns:
213
- Formatted string showing object values
214
- """
215
- from io import StringIO
216
-
217
- from mud.commands.build import _oedit_show
218
-
219
- output = StringIO()
220
- _oedit_show(output, obj.prototype if hasattr(obj, "prototype") else obj)
221
- return output.getvalue()
222
-
223
-
224
- def wear_loc_lookup(token: str):
225
- """Convert wear location token to WearLocation enum.
226
-
227
- ROM parity: src/olc_act.c:wear_loc (line 1967)
228
-
229
- Args:
230
- token: Wear location name (e.g., "head", "body", "wield")
231
-
232
- Returns:
233
- WearLocation enum value or None if invalid
234
- """
235
- from mud.commands.build import _resolve_wear_loc
236
-
237
- try:
238
- return _resolve_wear_loc(token)
239
- except (ValueError, KeyError):
240
- return None
241
-
242
-
243
- def show_flag_cmds() -> str:
244
- """Display available room flags for OLC.
245
-
246
- ROM parity: src/olc_act.c:show_flag_cmds (line 126)
247
-
248
- Returns:
249
- Formatted string listing available room flags
250
- """
251
- from mud.models.constants import RoomFlag
252
-
253
- flags = []
254
- for flag in RoomFlag:
255
- # Skip zero value (no flags set)
256
- if flag.value != 0:
257
- flags.append(f"{flag.name.lower():20} - {flag.value}")
258
-
259
- return "Available room flags:\n" + "\n".join(flags)
260
-
261
-
262
- # =============================================================================
263
- # Misc Utility Functions Public API
264
- # =============================================================================
265
-
266
-
267
- def check_blind(char: Character) -> bool:
268
- """Check if character is blind (cannot see).
269
-
270
- ROM parity: src/act_info.c:check_blind (line 542)
271
-
272
- Args:
273
- char: Character to check
274
-
275
- Returns:
276
- True if character can see, False if blind
277
- """
278
- from mud.models.constants import AffectFlag
279
-
280
- checker = getattr(char, "has_affect", None)
281
- if callable(checker):
282
- try:
283
- return not bool(checker(AffectFlag.BLIND))
284
- except Exception:
285
- pass
286
-
287
- affected = getattr(char, "affected_by", 0)
288
- try:
289
- return not bool(int(affected) & int(AffectFlag.BLIND))
290
- except Exception:
291
- return True
292
-
293
-
294
- def substitute_alias(char: Character, input_text: str) -> str:
295
- """Expand aliases in command input.
296
-
297
- ROM parity: src/alias.c:substitute_alias (line 41)
298
-
299
- Args:
300
- char: Character whose aliases to use
301
- input_text: Command input to expand
302
-
303
- Returns:
304
- Expanded command text with aliases substituted
305
- """
306
- from mud.commands.dispatcher import _expand_aliases
307
-
308
- return _expand_aliases(char, input_text)[0]
309
-
310
-
311
- def mult_argument(argument: str, number_str: str) -> tuple[int, str]:
312
- """Parse multiplier from argument (e.g., "5.sword" -> 5, "sword").
313
-
314
- ROM parity: src/interp.c:mult_argument (line 743)
315
-
316
- Used for shop commands like "buy 5 bread".
317
-
318
- Args:
319
- argument: Full argument string
320
- number_str: Pre-extracted number portion (unused in Python version)
321
-
322
- Returns:
323
- Tuple of (quantity, item_name)
324
- """
325
- from mud.commands.shop import _parse_purchase_quantity
326
-
327
- try:
328
- quantity, item = _parse_purchase_quantity(argument)
329
- return (quantity, item)
330
- except Exception:
331
- return (1, argument)
332
-
333
-
334
- # =============================================================================
335
- # Additional OLC Helper Functions
336
- # =============================================================================
337
-
338
-
339
- def set_obj_values(obj: Object, value_num: int, value: str) -> bool:
340
- """Parse and set object value by index.
341
-
342
- ROM parity: src/olc_act.c:set_value (line 543)
343
-
344
- Args:
345
- obj: Object to modify
346
- value_num: Value index (0-4)
347
- value: String value to parse and set
348
-
349
- Returns:
350
- True if value was set successfully, False otherwise
351
- """
352
- if not (0 <= value_num <= 4):
353
- return False
354
-
355
- try:
356
- obj.value[value_num] = int(value)
357
- return True
358
- except (ValueError, IndexError):
359
- return False
360
-
361
-
362
- def check_range(lower: int, upper: int) -> bool:
363
- """Validate numeric range.
364
-
365
- ROM parity: src/olc.c:check_range (line 201)
366
-
367
- Args:
368
- lower: Lower bound
369
- upper: Upper bound
370
-
371
- Returns:
372
- True if range is valid (lower <= upper)
373
- """
374
- return lower <= upper
375
-
376
-
377
- def wear_bit(location: str) -> int:
378
- """Convert wear location name to bit flag.
379
-
380
- ROM parity: src/olc_act.c:wear_bit (line 891)
381
-
382
- Args:
383
- location: Wear location name
384
-
385
- Returns:
386
- Wear bit flag value, or 0 if invalid
387
- """
388
- from mud.commands.build import _resolve_wear_loc
389
-
390
- loc = _resolve_wear_loc(location)
391
- if loc is None:
392
- return 0
393
-
394
- return 1 << int(loc)
395
-
396
-
397
- def show_liqlist() -> str:
398
- """Display available liquid types for containers.
399
-
400
- ROM parity: src/olc_act.c:show_liqlist (line 723)
401
-
402
- Returns:
403
- Formatted string listing liquid types
404
- """
405
- from mud.models.constants import LIQUID_TABLE
406
-
407
- liquids = []
408
- for idx, liq in enumerate(LIQUID_TABLE):
409
- liquids.append(f"{liq.name:20} - {idx}")
410
-
411
- return "Available liquid types:\n" + "\n".join(liquids)
412
-
413
-
414
- def show_damlist() -> str:
415
- """Display available damage types for weapons.
416
-
417
- ROM parity: src/olc_act.c:show_damlist (line 798)
418
-
419
- Returns:
420
- Formatted string listing damage types
421
- """
422
- from mud.models.constants import DamageType
423
-
424
- damages = []
425
- for dam in DamageType:
426
- damages.append(f"{dam.name.lower():20} - {dam.value}")
427
-
428
- return "Available damage types:\n" + "\n".join(damages)
429
-
430
-
431
- def show_skill_cmds() -> str:
432
- """Format skill list for display.
433
-
434
- ROM parity: src/olc_act.c:show_skill (line 1021)
435
-
436
- Returns:
437
- Formatted string listing all skills
438
- """
439
- from mud.world.world_state import skill_registry
440
-
441
- if not skill_registry or not hasattr(skill_registry, "skills"):
442
- return "Skills not loaded."
443
-
444
- skills = list(skill_registry.skills.keys())
445
-
446
- return "Available skills:\n" + "\n".join(f" {skill}" for skill in sorted(skills))
447
-
448
-
449
- def show_spec_cmds() -> str:
450
- """Format special function list for display.
451
-
452
- ROM parity: src/olc_act.c:show_spec (line 1089)
453
-
454
- Returns:
455
- Formatted string listing available special functions
456
- """
457
- specs = [
458
- "spec_breath_any",
459
- "spec_breath_acid",
460
- "spec_breath_fire",
461
- "spec_breath_frost",
462
- "spec_breath_gas",
463
- "spec_breath_lightning",
464
- "spec_cast_adept",
465
- "spec_cast_cleric",
466
- "spec_cast_judge",
467
- "spec_cast_mage",
468
- "spec_cast_undead",
469
- "spec_executioner",
470
- "spec_fido",
471
- "spec_guard",
472
- "spec_janitor",
473
- "spec_mayor",
474
- "spec_poison",
475
- "spec_thief",
476
- "spec_nasty",
477
- "spec_troll_member",
478
- "spec_ogre_member",
479
- "spec_patrolman",
480
- ]
481
-
482
- return "Available special functions:\n" + "\n".join(f" {spec}" for spec in sorted(specs))
483
-
484
-
485
- def show_version() -> str:
486
- """Show OLC version information.
487
-
488
- ROM parity: src/olc.c:show_version (line 93)
489
-
490
- Returns:
491
- OLC version string
492
- """
493
- return "QuickMUD OLC v1.0 - Python ROM 2.4b Port"
494
-
495
-
496
- def change_exit(room, direction: str, command: str, argument: str) -> str:
497
- """Edit room exit in specified direction.
498
-
499
- ROM parity: src/olc_act.c:change_exit (line 2201)
500
-
501
- Args:
502
- room: Room to modify
503
- direction: Direction name (north, south, etc.)
504
- command: Edit command (create, delete, to, key, name, desc)
505
- argument: Command argument
506
-
507
- Returns:
508
- Status message
509
- """
510
- from mud.commands.build import _redit_handle_exit
511
-
512
- return _redit_handle_exit(room, direction, command, argument)
513
-
514
-
515
- def show_help() -> str:
516
- """Show OLC editor help.
517
-
518
- ROM parity: src/olc_act.c:show_help (line 165)
519
-
520
- Returns:
521
- Help text for OLC commands
522
- """
523
- return """OLC Editor Commands:
524
-
525
- show - Display current object/room/mob
526
- create - Create new item
527
- edit - Edit existing item
528
- delete - Delete item
529
- list - List items
530
- save - Save changes to disk
531
- done - Exit editor
532
-
533
- For specific editor help, use: help aedit, help redit, help oedit, help medit
534
- """
535
-
536
-
537
- def add_reset(area, reset_type: str, args: list[int]) -> bool:
538
- """Add reset command to area.
539
-
540
- ROM parity: src/olc_act.c:add_reset (line 3412)
541
-
542
- Args:
543
- area: Area to modify
544
- reset_type: Reset type ('M', 'O', 'P', 'G', 'E', 'D', 'R')
545
- args: Reset arguments (vnums, limits, etc.)
546
-
547
- Returns:
548
- True if reset was added successfully
549
- """
550
- from mud.loaders.reset_loader import Reset
551
-
552
- try:
553
- reset = Reset(
554
- command=reset_type,
555
- arg1=args[0] if len(args) > 0 else 0,
556
- arg2=args[1] if len(args) > 1 else 0,
557
- arg3=args[2] if len(args) > 2 else 0,
558
- arg4=args[3] if len(args) > 3 else 0,
559
- )
560
-
561
- if not hasattr(area, "resets"):
562
- area.resets = []
563
-
564
- area.resets.append(reset)
565
- return True
566
- except Exception:
567
- return False
568
-
569
-
570
- # =============================================================================
571
- # Admin Utility Functions
572
- # =============================================================================
573
-
574
-
575
- def do_imotd(char: Character) -> str:
576
- """Display immortal message of the day.
577
-
578
- ROM parity: src/act_wiz.c:do_imotd (line 1021)
579
-
580
- Args:
581
- char: Character requesting IMOTD
582
-
583
- Returns:
584
- IMOTD text or error message
585
- """
586
- from mud.commands.help import do_help
587
-
588
- return do_help(char, "imotd")
589
-
590
-
591
- def do_rules(char: Character) -> str:
592
- """Display game rules.
593
-
594
- ROM parity: src/act_comm.c:do_rules (line 892)
595
-
596
- Args:
597
- char: Character requesting rules
598
-
599
- Returns:
600
- Rules text or error message
601
- """
602
- from mud.commands.help import do_help
603
-
604
- return do_help(char, "rules")
605
-
606
-
607
- def do_story(char: Character) -> str:
608
- """Display game story/background.
609
-
610
- ROM parity: src/act_comm.c:do_story (line 912)
611
-
612
- Args:
613
- char: Character requesting story
614
-
615
- Returns:
616
- Story text or error message
617
- """
618
- from mud.commands.help import do_help
619
-
620
- return do_help(char, "story")
621
-
622
-
623
- def get_max_train(char: Character, stat: str) -> int:
624
- """Calculate maximum stat training limit for character.
625
-
626
- ROM parity: src/act_wiz.c:get_max_train (line 2543)
627
-
628
- Args:
629
- char: Character to check
630
- stat: Stat name (str, int, wis, dex, con)
631
-
632
- Returns:
633
- Maximum trainable value for stat
634
- """
635
- base_max = 18
636
- race_bonus = 3
637
- max_possible = 25
638
-
639
- if hasattr(char, "pcdata") and char.pcdata:
640
- return min(base_max + race_bonus, max_possible)
641
-
642
- return base_max
643
-
644
-
645
- def recursive_clone(obj: Object, clone_to: Object | None = None) -> Object:
646
- """Deep clone object including all contents.
647
-
648
- ROM parity: src/act_wiz.c:recursive_clone (line 2320)
649
-
650
- Recursively clones an object and all objects contained within it.
651
- This is used by OLC and clone commands to duplicate complex items.
652
-
653
- Args:
654
- obj: Object to clone
655
- clone_to: Parent object to add clone to (None for standalone)
656
-
657
- Returns:
658
- Cloned object with all contents
659
- """
660
- from mud.models.obj import ObjIndex
661
- from mud.models.object import Object, create_object
662
-
663
- if not obj.prototype:
664
- proto = ObjIndex(
665
- vnum=obj.vnum,
666
- name=obj.name,
667
- short_descr=obj.short_descr,
668
- long_descr=obj.long_descr,
669
- description=obj.description,
670
- item_type=obj.item_type,
671
- extra_flags=obj.extra_flags,
672
- wear_flags=obj.wear_flags,
673
- value=obj.value.copy() if obj.value else [0, 0, 0, 0, 0],
674
- weight=obj.weight,
675
- cost=obj.cost,
676
- level=obj.level,
677
- )
678
- else:
679
- proto = obj.prototype
680
-
681
- new_obj = create_object(proto)
682
-
683
- for content in obj.contained_items:
684
- recursive_clone(content, new_obj)
685
-
686
- if clone_to:
687
- clone_to.contained_items.append(new_obj)
688
- new_obj.location = None
689
-
690
- return new_obj