· 5 years ago · Mar 22, 2020, 03:46 AM
1"""
2Commands
3
4Commands describe the input the account can do to the game.
5
6"""
7
8from evennia import Command as BaseCommand
9from evennia.commands.default.building import ObjManipCommand
10from evennia import InterruptCommand
11from evennia.utils.evmenu import EvMenu
12from evennia.utils import create, inherits_from
13from world import skillsets, attack_desc
14from world.generic_str import article
15
16
17class Command(BaseCommand):
18 """
19 Inherit from this if you want to create your own command styles
20 from scratch. Note that Evennia's default commands inherits from
21 MuxCommand instead.
22
23 Note that the class's `__doc__` string (this text) is
24 used by Evennia to create the automatic help entry for
25 the command, so make sure to document consistently here.
26
27 Each Command implements the following methods, called
28 in this order (only func() is actually required):
29 - at_pre_cmd(): If this returns anything truthy, execution is aborted.
30 - parse(): Should perform any extra parsing needed on self.args
31 and store the result on self.
32 - func(): Performs the actual work.
33 - at_post_cmd(): Extra actions, often things done after
34 every command, like prompts.
35 """
36 pass
37
38class CmdDesc(Command):
39 key = "desc"
40 def func(self):
41 caller = self.caller
42 desc = caller.desc()
43 self.msg(desc)
44
45class CmdCharGen(Command):
46 key = "chargen"
47
48 def func(self):
49 caller = self.caller
50 EvMenu(caller, "world.chargen", startnode="main", cmd_on_exit="look", cmdset_mergetype="Replace", cmdset_priority=1,
51 auto_quit=True, auto_look=True, auto_help=True)
52
53class CmdLearnSkill(Command):
54 key = 'learn'
55 """
56 Usage: learn <skillset> <skill>
57 """
58
59 def parse(self):
60 caller = self.caller
61 args = self.args.lstrip()
62 try:
63 self.skillset, self.skill = args.split(" ", 1)
64 except ValueError:
65 caller.msg("Usage: learn <skillset> <skill>")
66 raise InterruptCommand
67
68 if self.skillset not in skillsets.VIABLE_SKILLSETS:
69 caller.msg(f"{self.skillset} is not a viable skillset!")
70 raise InterruptCommand
71 if self.skill not in skillsets.VIABLE_SKILLS:
72 caller.msg(f"{self.skill} is not a viable skill of {self.skillset}!")
73 raise InterruptCommand
74
75 def func(self):
76 caller = self.caller
77 if not self.args:
78 caller.msg('Usage: learn <skillset> <skill>')
79 return
80
81 skillsets.learn_skill(self.caller, self.skillset, self.skill)
82
83class CmdGrantSP(Command):
84 key = '@grant-sp'
85 '''
86 Usage: @grant-sp <person> <number> <skillset>
87 '''
88 def parse(self):
89 caller = self.caller
90 args = self.args.lstrip()
91 try:
92 self.person, self.number, self.skillset = args.split(" ", 2)
93 except ValueError:
94 caller.msg("Requires 3 arguments. Usage: @grant-sp <person> <number> <skillset>")
95 raise InterruptCommand
96
97 self.char = caller.search(self.person)
98 if not self.char:
99 raise InterruptCommand
100
101 try:
102 self.number = int(self.number)
103 except ValueError:
104 caller.msg("The number must be an integer.")
105 raise InterruptCommand
106 print(f"Viable Skillsets: {skillsets.VIABLE_SKILLSETS}")
107 if self.skillset not in skillsets.VIABLE_SKILLSETS:
108 caller.msg(f"{self.skillset} is not a viable skillset!")
109 raise InterruptCommand
110
111 def func(self):
112 caller = self.caller
113 char = self.char
114 num = self.number
115 skillset = self.skillset
116 skillset = char.attributes.get(skillset)
117 skillset['total_sp'] += num
118 caller.msg(f'Granted {char} {num} skillpoints in {self.skillset}.')
119
120class CmdTest(Command):
121 key = 'testy'
122
123 def func(self):
124 caller = self.caller
125 caller.msg("This should be an image!")
126 caller.msg(image="https://i.imgur.com/2Wo1BpT.png")
127 caller.msg(video="https://youtu.be/YUOxwynb9UU")
128 caller.msg(video="https://vimeo.com/358147193")
129
130# class CmdCreate(ObjManipCommand):
131# """
132# create new objects
133# Usage:
134# create[/drop] <objname>[;alias;alias...][:typeclass], <objname>...
135# switch:
136# drop - automatically drop the new object into your current
137# location (this is not echoed). This also sets the new
138# object's home to the current location rather than to you.
139# Creates one or more new objects. If typeclass is given, the object
140# is created as a child of this typeclass. The typeclass script is
141# assumed to be located under types/ and any further
142# directory structure is given in Python notation. So if you have a
143# correct typeclass 'RedButton' defined in
144# types/examples/red_button.py, you could create a new
145# object of this type like this:
146# create/drop button;red : examples.red_button.RedButton
147# """
148
149# key = "create"
150# switch_options = ("drop",)
151# locks = "cmd:perm(create) or perm(Builder)"
152# help_category = "Building"
153
154# # lockstring of newly created objects, for easy overloading.
155# # Will be formatted with the {id} of the creating object.
156# new_obj_lockstring = "control:id({id}) or perm(Admin);delete:id({id}) or perm(Admin)"
157
158# def func(self):
159# """
160# Creates the object.
161# """
162
163# caller = self.caller
164
165# if not self.args:
166# string = "Usage: create[/drop] <newname>[;alias;alias...] [:typeclass.path]"
167# caller.msg(string)
168# return
169
170# # create the objects
171# for objdef in self.lhs_objs:
172# string = ""
173# name = objdef['name']
174# art = article(name)
175# name = f"{art} {name}"
176# aliases = objdef['aliases']
177# typeclass = objdef['option']
178
179# # create object (if not a valid typeclass, the default
180# # object typeclass will automatically be used)
181# lockstring = self.new_obj_lockstring.format(id=caller.id)
182# obj = create.create_object(typeclass, name, caller,
183# home=caller, aliases=aliases,
184# locks=lockstring, report_to=caller)
185# if not obj:
186# continue
187# if aliases:
188# string = "You create a new %s: %s (aliases: %s)."
189# string = string % (obj.typename, obj.name, ", ".join(aliases))
190# else:
191# string = "You create a new %s: %s."
192# string = string % (obj.typename, obj.name)
193# # set a default desc
194# if not obj.db.desc:
195# obj.db.desc = "You see nothing special."
196# if 'drop' in self.switches:
197# if caller.location:
198# obj.home = caller.location
199# obj.move_to(caller.location, quiet=True)
200# if string:
201# caller.msg(string)
202
203class CmdInventory(Command):
204 """
205 Shows your inventory.
206
207 Usage:
208 inventory
209 inv
210 i
211 """
212 key = "inventory"
213 aliases = ["inv", "i"]
214 locks = "cmd:all()"
215
216 def func(self):
217 """check inventory"""
218
219 caller = self.caller
220 items = caller.contents
221 left_hand, right_hand = caller.db.hands.values()
222
223 # Remove hands and append all other items to a new list.
224 filtered_items = []
225 for i in items:
226 if i not in [left_hand, right_hand]:
227 filtered_items.append(i)
228
229 if not filtered_items:
230 string = "Your inventory is empty."
231 else:
232 table = self.styled_table(border="header")
233 for item in filtered_items:
234 table.add_row(f"|C{item.name}|n {item.db.desc or ''}")
235 string = f"|wYou are carrying:\n{table}"
236 caller.msg(string)
237
238class CmdInhand(Command):
239 key = 'inhand'
240 aliases = 'inh'
241
242 def func(self):
243 caller = self.caller
244
245 left_wield, right_wield, both_wield = caller.db.wielding.values()
246
247 left_hand, right_hand = caller.db.hands.values()
248
249 if left_hand:
250 left_item = left_hand.name
251 else:
252 left_item = 'nothing'
253
254 if right_hand:
255 right_item = right_hand.name
256 else:
257 right_item = 'nothing'
258
259 if not left_hand and not right_hand:
260 caller.msg(f"Your hands are empty.")
261 return
262
263
264 if left_wield and not right_wield:
265 caller.msg(f"You are wielding {left_item} in your left hand and holding {right_item} in your right hand.")
266 elif right_wield and not left_wield:
267 caller.msg(f"You are holding {left_item} in your left hand and wielding {right_item} in your right hand.")
268 elif left_wield and right_wield:
269 caller.msg(f"You are wielding {left_item} in your left hand and {right_item} in your right hand.")
270 elif both_wield:
271 caller.msg(f"You are wielding {right_item} in both hands.")
272 else:
273 caller.msg(f"You are holding {left_item} in your left hand and {right_item} in your right hand.")
274
275class CmdStand(Command):
276 key = 'stand'
277 def func(self):
278 caller = self.caller
279 db = caller.db
280 if db.standing:
281 caller.msg("You are already standing.")
282 return
283 else:
284 db.standing = True
285 db.kneeling = False
286 db.sitting = False
287 db.lying = False
288 caller.msg("You stand up.")
289
290class CmdSit(Command):
291 key = 'sit'
292 def func(self):
293 caller = self.caller
294 db = caller.db
295 if db.sitting:
296 caller.msg("You are already sitting.")
297 else:
298 db.standing = False
299 db.kneeling = False
300 db.sitting = True
301 db.lying = False
302 caller.msg("You sit down.")
303
304class CmdKneel(Command):
305 key = 'kneel'
306 def func(self):
307 caller = self.caller
308 db = caller.db
309 if db.kneeling:
310 caller.msg("You are already kneeling.")
311 else:
312 db.standing = False
313 db.kneeling = True
314 db.sitting = False
315 db.lying = False
316 caller.msg("You kneel.")
317
318class CmdLie(Command):
319 key = 'lie'
320 aliases = ['lay',]
321 def func(self):
322 caller = self.caller
323 db = caller.db
324 if db.lying:
325 caller.msg("You are already lying down.")
326 else:
327 db.standing = False
328 db.kneeling = False
329 db.sitting = False
330 db.lying = True
331 caller.msg("You lie down.")
332
333
334class CmdGet(Command):
335 """
336 Pick up something.
337
338 Usage:
339 get <obj>
340 take <obj>
341
342 Gets an object from your inventory or location and places it in your hands.
343 """
344 key = "get"
345 aliases = ["take",]
346 locks = "cmd:all()"
347
348
349 def func(self):
350 """Implements the command."""
351 #TODO: Fix the missing echo when picking up an item while wielding in both hands.
352 #TODO: Allow auto-stow of items in hand and continue to pick up obj if more than one exists in location.
353 caller = self.caller
354 if not self.args:
355 caller.msg("Get what?")
356 return
357 args = self.args.strip()
358
359 left_wield, right_wield, both_wield = caller.db.wielding.values()
360 left_hand, right_hand = caller.db.hands.values()
361
362
363 obj = caller.search(args, location=[caller.location, caller], quiet=True)
364 if not obj:
365 self.caller.msg(f"|r{args} cannot be found.|n")
366 return
367 if len(obj) > 1:
368 obj = obj[0]
369 if caller == obj:
370 caller.msg("You can't get yourself.")
371 return
372 if not obj.access(caller, 'get'):
373 if obj.db.get_err_msg:
374 caller.msg(obj.db.get_err_msg)
375 else:
376 caller.msg("You can't get that.")
377 return
378 if obj in [left_hand, right_hand]:
379 caller.msg(f"You are already carrying {obj.name}.")
380 return
381
382 # calling at_before_get hook method
383 if not obj.at_before_get(caller):
384 return
385
386 # Check if wielding a single weapon/shield in left hand and stow it.
387 if left_wield:
388 caller.msg(f"You stop wielding {left_hand.name} and stow it away.")
389 caller.db.hands['left'] = None
390 caller.db.wielding['left'] = None
391
392 # If both hands have objects, stow the dominate hand.
393 if right_hand and left_hand:
394 caller.msg(f"You stow away {right_hand.name}.")
395 caller.location.msg_contents(f"{caller.name} stows away {right_hand.name}.", exclude=caller)
396 caller.db.hands['right'] = None
397
398 # Wielding with both hands technically only holds the item in the right hand (for now).
399 # So we already know the left hand is free to get items.
400 if both_wield:
401 caller.msg(f"You stop wielding {both_wield.name}.")
402 caller.location.msg_contents(f"{caller.name} stops wielding {both_wield.name}.", exclude=caller)
403 caller.db.wielding['both'] = None
404
405 # Decide the location of the item and echo it.
406 elif obj.location == caller:
407 caller.msg(f"You get {obj.name} from your inventory.")
408 caller.location.msg_contents(f"{caller.name} gets {obj.name} from their inventory.", exclude=caller)
409 elif obj.location == caller.location:
410 caller.msg(f"You pick up {obj.name}.")
411 caller.location.msg_contents(f"{caller.name} picks up {obj.name}.", exclude=caller)
412
413 if right_hand and not left_hand:
414 caller.db.hands['left'] = obj
415 else:
416 caller.db.hands['right'] = obj
417
418 obj.move_to(caller, quiet=True)
419
420 # calling at_get hook method
421 obj.at_get(caller)
422
423class CmdDrop(Command):
424 """
425 drop something
426 Usage:
427 drop <obj>
428 Lets you drop an object from your inventory into the
429 location you are currently in.
430 """
431
432 key = "drop"
433 locks = "cmd:all()"
434
435
436 def func(self):
437 """Implement command"""
438
439 caller = self.caller
440 if not self.args:
441 caller.msg("Drop what?")
442 return
443 args = self.args.strip()
444
445 left_hand, right_hand = caller.db.hands.values()
446
447 wielding = caller.db.wielding
448 left_wield, right_wield, both_wield = wielding.values()
449
450 obj = caller.search(args, location=[caller, caller.location], quiet=True)
451 if not obj:
452 caller.msg(f"|rYou are not in possession of {args}.|n")
453 return
454
455 if len(obj):
456 obj = obj[0]
457
458 # Call the object script's at_before_drop() method.
459 if not obj.at_before_drop(caller):
460 return
461
462
463 if obj in [left_hand, right_hand]:
464 # If the object is currently wielded, stop wielding it and drop it.
465 if obj in [left_wield, right_wield, both_wield]:
466 caller.msg(f"You stop wielding {obj.name} and drop it.")
467 caller.location.msg_contents(f"{caller.name} stops wielding {obj.name} and drops it.", exclude=caller)
468 if left_wield:
469 wielding['left'] = None
470 else:
471 wielding['right'], wielding['both'] = None, None
472 else:
473 caller.msg(f"You drop {obj.name}.")
474 caller.location.msg_contents(f"{caller.name} drops {obj.name}.", exclude=caller)
475 if obj == left_hand:
476 caller.db.hands['left'] = None
477 else:
478 caller.db.hands['right'] = None
479 elif obj.location == caller:
480 caller.msg(f"You pull {obj.name} from your inventory and drop it on the ground.")
481 caller.location.msg_contents(f"{caller.name} pulls {obj.name} from their inventory and drops it on the ground.", exclude=caller)
482 elif obj.location == caller.location:
483 caller.msg(f"The {obj.name} is already on the ground.")
484 return
485
486 obj.move_to(caller.location, quiet=True)
487
488 # Call the object script's at_drop() method.
489 obj.at_drop(caller)
490
491class CmdStow(Command):
492 """
493 pick up something
494 Usage:
495 get <obj>
496 Picks up an object from your location and puts it in
497 your inventory.
498 """
499
500 key = 'stow'
501 locks = 'cmd:all()'
502
503
504 def func(self):
505 """implements the command."""
506 caller = self.caller
507 if not self.args:
508 caller.msg("Stow what?")
509 return
510 args = self.args.strip()
511
512 left_hand, right_hand = caller.db.hands.values()
513 wielding = caller.db.wielding
514 left_wield, right_wield, both_wield = wielding.values()
515
516 obj = caller.search(args, location=[caller.location, caller],
517 nofound_string=f"You can't find {args}.",
518 multimatch_string=f"There are more than one {args}.")
519 if not obj:
520 return
521 if caller == obj:
522 caller.msg("You can't get yourself.")
523 return
524 if not obj.access(caller, 'get'):
525 if obj.db.get_err_msg:
526 caller.msg(obj.db.get_err_msg)
527 else:
528 caller.msg("You can't get that.")
529 return
530
531 # calling at_before_get hook method
532 if not obj.at_before_get(caller):
533 return
534
535 if obj in [left_hand, right_hand]:
536 # If the stowed object is currently wielded, stop wielding it and stow it.
537 if obj in [left_wield, right_wield, both_wield]:
538 caller.msg(f"You stop wielding {obj.name} and stow it away.")
539 caller.location.msg_contents(f"{caller.name} stops wielding {obj.name} and stows it away.", exclude=caller)
540 if obj == left_wield:
541 wielding['left'] = None
542 elif obj == right_wield:
543 wielding['right'] = None
544 else:
545 wielding['both'] = None
546 else:
547 caller.msg(f"You stow away {obj.name}.")
548 caller.location.msg_contents(f"{caller.name} stows away {obj.name}.", exclude=caller)
549 if obj == left_hand:
550 caller.db.hands['left'] = None
551 else:
552 caller.db.hands['right'] = None
553 elif obj.location == caller.location:
554 caller.msg(f"You pick up {obj.name} and stow it away.")
555 caller.location.msg_contents(f"{caller.name} picks up {obj.name} and stows it away.", exclude=caller)
556 obj.move_to(caller, quiet=True)
557 elif obj.location == caller:
558 caller.msg(f"You already have {obj.name} in your inventory.")
559 return
560
561 # calling at_get hook method
562 obj.at_get(caller)
563
564class CmdWield(Command):
565 """
566 Wield a weapon.
567
568 Usage: wield <weapon>
569 """
570 key = 'wield'
571
572 def func(self):
573 caller = self.caller
574 if not self.args:
575 caller.msg("Usage: wield <weapon>")
576 return
577 args = self.args.strip()
578 left_hand, right_hand = caller.db.hands.values()
579 left_wield, right_wield, both_wield = caller.db.wielding.values()
580
581 obj = caller.search(args, location=[caller],
582 nofound_string="You must be holding a weapon to wield it.",
583 multimatch_string=f"There are more than one {args}.")
584 if not obj:
585 return
586 if obj == caller:
587 caller.msg("You can't wield yourself.")
588 return
589 if not obj.attributes.get('wieldable'):
590 caller.msg("That's not a wieldable item.")
591 if obj in [left_wield, right_wield, both_wield]: # Check for an item already wielded.
592 caller.msg(f"You are already wielding {obj.name}.")
593 return
594
595 hands_req = obj.attributes.get('wieldable')
596
597 # Right hand is dominate.
598
599
600 if obj not in [left_hand, right_hand]: # Automagically get the object from the inventory.
601 if right_hand and not right_wield:
602 caller.msg(f"You stow away {right_hand.name}.")
603 caller.location.msg_contents(f"{caller.name} stows away {right_hand.name}.", exclude=caller)
604 caller.db.hands['right'] = None
605 caller.msg(f"You get {obj.name} from your inventory.")
606 caller.location.msg_contents(f"{caller.name} gets {obj.name} from their inventory.", exclude=caller)
607 caller.db.hands['right'] = obj
608 # Refresh hand variables before the next check.
609 left_hand, right_hand = caller.db.hands.values()
610
611
612 if obj in [left_hand, right_hand]:
613 if hands_req == 1:
614 if inherits_from(obj, 'typeclasses.objects.OffHand'): #For wielding shields.
615 if obj == right_hand and not right_wield:
616 if left_hand: # If theres any item in the left hand, stow it first.
617 caller.db.hands['left'] = None
618 caller.msg(f"You stow away {left_hand.name}.")
619 caller.location.msg_contents(f"{caller.name} stows away {left_hand.name}.", exclude=caller)
620 # Send the offhand weapon to the left hand.
621 caller.db.hands['right'] = None
622 caller.db.hands['left'] = obj
623 caller.msg(f"You swap {obj.name} to your left hand.")
624 caller.location.msg_contents(f"{caller.name} swaps {obj.name} to their left hand.", exclude=caller)
625 # Offhand item is certainly already in the left hand.
626 caller.msg(f"You wield {obj.name} in your left hand.")
627 caller.location.msg_contents(f"{caller.name} wields {obj.name} in their left hand.", exclude=caller)
628 caller.db.wielding['left'] = obj
629 elif obj == left_hand and not inherits_from(obj, 'typeclasses.objects.OffHand'): # Make sure the item is a main hand wield.
630 caller.msg(f"You swap the contents of your hands and wield {obj.name} in your right hand.")
631 caller.location.msg_contents(f"{caller.name} swaps the content of their hands "
632 f"and wields {obj.name} in their right hand.", exclude=caller)
633 caller.db.hands['right'] = obj
634 if right_hand:
635 caller.db.hands['right'] = None
636 caller.db.hands['left'] = obj
637 caller.db.wielding['right'] = obj
638 elif obj == right_hand and not inherits_from(obj, 'typeclasses.objects.OffHand'): # Make sure the item is a main hand wield.
639 caller.msg(f"You wield {obj.name} in your right hand.")
640 caller.location.msg_contents(f"{caller.name} wields {obj.name} in their right hand.", exclude=caller)
641 caller.db.wielding['right'] = obj
642 elif hands_req == 2:
643 if obj == left_hand:
644 if right_hand:
645 caller.msg(f"You stow away {right_hand.name}.")
646 caller.location.msg_contents(f"{caller.name} stows away {right_hand}.", exclude=caller)
647 caller.db.hands['right'] = None
648 elif obj == right_hand:
649 if left_hand:
650 caller.msg(f"You stow away {left_hand.name}.")
651 caller.location.msg_contents(f"{caller.name} stows away {left_hand}.", exclude=caller)
652 caller.db.hands['left'] = None
653 caller.msg(f"You wield {obj.name} in both hands.")
654 caller.location.msg_contents(f"{caller.name} wields {obj.name} in both hands.", exclude=caller)
655 caller.db.wielding['both'] = obj
656 elif obj.location == caller.location:
657 caller.msg(f"You must be carrying a weapon to wield it.")
658 return
659
660class CmdUnwield(Command):
661 """
662 Unwield a weapon.
663 Usage: unwield
664 """
665
666 key = 'unwield'
667
668 def func(self):
669 caller = self.caller
670 wielding = caller.db.wielding
671 left_wield, right_wield, both_wield = wielding.values()
672
673 if left_wield:
674 caller.msg(f"You stop wielding {left_wield.name} in your offhand.")
675 caller.location.msg_contents(f"{caller.name} stops wielding {left_wield.name} in their offhand.", exclude=caller)
676 wielding['left'] = None
677 elif right_wield and not left_wield:
678 caller.msg(f"You stop wielding {right_wield.name}.")
679 caller.location.msg_contents(f"{caller.name} stops wielding {right_wield.name}.", exclude=caller)
680 wielding['right'] = None
681 else:
682 caller.msg(f"You stop wielding {both_wield.name}.")
683 caller.location.msg_contents(f"{caller.name} stops wielding {both_wield.name}.", exclude=caller)
684 wielding['both'] = None
685
686class CmdLook(Command):
687 """
688 look at location or object
689 Usage:
690 look
691 look <obj>
692 look *<account>
693 Observes your location or objects in your vicinity.
694 """
695 key = "look"
696 aliases = ["l", "ls"]
697 locks = "cmd:all()"
698
699 def func(self):
700 """
701 Handle the looking.
702 """
703 caller = self.caller
704 if not self.args:
705 target = caller.location
706 if not target:
707 caller.msg("You have no location to look at!")
708 return
709 else:
710 args = self.args.strip()
711 if args == 'crowd':
712 self.caller.location.crowd(self.caller)
713 return
714 else:
715 target = caller.search(args, location=[caller, caller.location])
716 if not target:
717 return
718 self.msg((caller.at_look(target), {'type': 'look'}), options=None)
719
720
721class CmdMatch(Command): #TODO: NOT FINISHED
722 """
723 Matches object in location or inventory.
724
725 Usage: match <object>
726 """
727 key = 'match'
728
729 def func(self):
730 if not self.args:
731 self.caller.msg("Usage: match <object>")
732 return
733
734 args = self.args.lstrip()
735
736 obj = self.caller.search(args, location=[self.caller.location, self.caller])
737
738 if not obj:
739 self.caller.msg(f"Could not find {self.args}.")
740 return
741 else:
742 self.caller.msg(f"Object found {self.args}.")
743 pass