cmd_manip.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. '''
  2. cmd_manip.py
  3. a set of commands that NakedMud(tm) comes with that allows characters to
  4. manipulate various things. These commands are mostly directed towards
  5. manipulating objects (e.g. get, put, drop, etc...) but can also affect other
  6. things like exits (e.g. open, close)
  7. '''
  8. import mudsys, mud, inform, utils, movement, hooks
  9. import obj as mudobj
  10. def do_give(ch, recv, obj):
  11. '''does the handling of the give command'''
  12. mud.message(ch, recv, obj, None, True, "to_room",
  13. "$n gives $o to $N.")
  14. mud.message(ch, recv, obj, None, True, "to_vict",
  15. "$n gives $o to you.")
  16. mud.message(ch, recv, obj, None, True, "to_char",
  17. "You give $o to $N.")
  18. obj.carrier = recv
  19. # run our give hook
  20. hooks.run("give", hooks.build_info("ch ch obj", (ch, recv, obj)))
  21. def cmd_give(ch, cmd, arg):
  22. '''Usage: give <object> [to] <person>
  23. Attempts to transfer an object from your inventory to the specified
  24. person. You can give multiple objects at a time by using the all.
  25. prefix. For example:
  26. > give all.cookie george
  27. Would give all of the cookies in your inventory to George. If you only
  28. want to give him the raisin cookie, which also happens to be the third
  29. cookie in your inventory, you can use a numeric prefix instead of
  30. the all prefix. For example:
  31. > give 3.cookie george'''
  32. try:
  33. to_give, multi, recv = mud.parse_args(ch, True, cmd, arg,
  34. "[the] obj.inv.multiple " +
  35. "[to] ch.room.noself")
  36. except: return
  37. if multi == False:
  38. do_give(ch, recv, to_give)
  39. else:
  40. for obj in to_give:
  41. do_give(ch, recv, obj)
  42. def do_get(ch, obj, cont):
  43. '''transfers an item from the ground to the character'''
  44. if utils.is_keyword(obj.bits, "notake"):
  45. ch.send("You cannot take " + ch.see_as(obj) + ".")
  46. elif cont != None:
  47. obj.carrier = ch
  48. mud.message(ch, None, obj, cont, True, "to_char", "You get $o from $O.")
  49. mud.message(ch, None, obj, cont, True, "to_room", "$n gets $o from $O.")
  50. else:
  51. obj.carrier = ch
  52. mud.message(ch, None, obj, None, True, "to_char", "You get $o.")
  53. mud.message(ch, None, obj, None, True, "to_room", "$n gets $o.")
  54. # run get hooks
  55. hooks.run("get", hooks.build_info("ch obj", (ch, obj)))
  56. def try_get_from(ch, cont, arg):
  57. '''tries to get one item from inside another'''
  58. if not cont.istype("container"):
  59. mud.message(ch, None, cont, None, True, "to_char",
  60. "$o is not a container.")
  61. elif cont.container_is_closed:
  62. mud.message(ch, None, cont, None, True, "to_char", "$o is closed.")
  63. else:
  64. # find our count and name
  65. num, name = utils.get_count(arg)
  66. # multi or single?
  67. if num == "all":
  68. list = utils.find_all_objs(ch, cont.objs, name)
  69. for obj in list:
  70. do_get(ch, obj, cont)
  71. else:
  72. # obj = find_obj(ch, cont.objs, num, name)
  73. obj = mudobj.find_obj(arg, cont, ch)
  74. if obj != None:
  75. do_get(ch, obj, cont)
  76. else:
  77. mud.message(ch, None, cont, None, True, "to_char",
  78. "You could not find what you were looking for in $o.")
  79. def cmd_get(ch, cmd, arg):
  80. '''Usage: get [the] <item> [[from] <other item>]
  81. Attempts to move an object from the room to your inventory. If an
  82. addition argument is supplied, the command assumes it is a container and
  83. instead tries to move an object from the container to your inventory.'''
  84. try:
  85. arg,cont = mud.parse_args(ch, True, cmd, arg,
  86. "[the] word(object) | [from] obj.room.inv.eq")
  87. except: return
  88. # are we doing get, or get-from?
  89. if cont != None:
  90. try_get_from(ch, cont, arg)
  91. else:
  92. # try to find the object in the room
  93. try:
  94. found,multi= mud.parse_args(ch, True, cmd, arg, "obj.room.multiple")
  95. except: return
  96. # pick up all the items we want
  97. if multi == False:
  98. do_get(ch, found, None)
  99. else:
  100. for obj in found:
  101. do_get(ch, obj, None)
  102. def do_drop(ch, obj):
  103. '''handles object dropping'''
  104. obj.room = ch.room
  105. mud.message(ch, None, obj, None, True, "to_char", "You drop $o.")
  106. mud.message(ch, None, obj, None, True, "to_room", "$n drops $o.")
  107. # run our drop hook
  108. hooks.run("drop", hooks.build_info("ch obj", (ch, obj)))
  109. def cmd_drop(ch, cmd, arg):
  110. '''Usage: drop <item>
  111. Attempts to move an object from your inventory to the ground.'''
  112. try:
  113. found,multi=mud.parse_args(ch, True, cmd, arg, "[the] obj.inv.multiple")
  114. except: return
  115. # are we dropping a list of things, or just one?
  116. if multi == False:
  117. do_drop(ch, found)
  118. else:
  119. for obj in found:
  120. do_drop(ch, obj)
  121. def do_remove(ch, obj):
  122. '''handles equipment removing'''
  123. # try to put it to our inventory
  124. obj.carrier = ch
  125. # make sure it succeeded
  126. if obj.carrier != ch:
  127. ch.send("You were unable to remove " + ch.see_as(obj) + ".")
  128. else:
  129. mud.message(ch, None, obj, None, True, "to_char", "You remove $o.")
  130. mud.message(ch, None, obj, None, True, "to_room", "$n removes $o.")
  131. # run our hooks
  132. hooks.run("remove", hooks.build_info("ch obj", (ch, obj)))
  133. def cmd_remove(ch, cmd, arg):
  134. '''Usage: remove <item | all>
  135. Attempts to remove an item you have equipped. If you would like to
  136. remove everything you are wearing, you may instead specify \'all\'
  137. instead of a specific item. If you would like to remove all of a certain
  138. type of object (for instance, rings) you can use an all. prefix. For
  139. example:
  140. > remove all.ring
  141. This command will remove everything you are wearing with the \'ring\'
  142. keyword. If you would instead like to remove, say, the second thing you
  143. are wearing with the \'ring\' keyword, you can supply a numeric prefix.
  144. For example:
  145. > remove 2.ring'''
  146. try:
  147. found,multi= mud.parse_args(ch, True, cmd, arg, "[the] obj.eq.multiple")
  148. except: return
  149. # are we removing one thing, or multiple things?
  150. if multi == False:
  151. do_remove(ch, found)
  152. else:
  153. for obj in found:
  154. do_remove(ch, obj)
  155. def do_wear(ch, obj, where):
  156. '''handles object wearing'''
  157. if not obj.istype("worn"):
  158. ch.send("But " + ch.see_as(obj) + " is not equippable.")
  159. elif ch.equip(obj, where):
  160. mud.message(ch, None, obj, None, True, "to_char", "You wear $o.")
  161. mud.message(ch, None, obj, None, True, "to_room", "$n wears $o.")
  162. # run our wear hook
  163. hooks.run("wear", hooks.build_info("ch obj", (ch, obj)))
  164. def cmd_wear(ch, cmd, arg):
  165. '''Usage: wear <item> [where]
  166. Attempts to equip an item from your inventory. If you would like to
  167. equip it to a non-default location, you can supply where on your body
  168. you would like to wear it. For example, if you would like to equip a
  169. torch, but in your offhand instead of your mainhand:
  170. > wear torch offhand
  171. If an item covers multiple locations on your body, you can specify where
  172. all you would like to equip the item as a comma-separated list:
  173. > wear gloves left hand, right hand'''
  174. try:
  175. found, multi, where = mud.parse_args(ch, True, cmd, arg,
  176. "[the] obj.inv.multiple | [on] string(bodyparts)")
  177. except: return
  178. # Are the things we're looking for not body positions? Try to catch this!
  179. # it will happen when someone enters multiple arguments for the name without
  180. # supplying ' and ' around it. The mud will misinterpret it as an item
  181. if not multi and where != None and not "," in where:
  182. # reparse what we want!
  183. if not where in ch.bodyparts:
  184. where = None
  185. try:
  186. found, = mud.parse_args(ch,True,cmd,"'"+arg+"'","[the] obj.inv")
  187. except: return
  188. # are we wearing one thing, or multiple things?
  189. if multi == False:
  190. do_wear(ch, found, where)
  191. else:
  192. for obj in found:
  193. do_wear(ch, obj, where)
  194. def do_put(ch, obj, cont):
  195. '''handles the putting of objects'''
  196. if obj == cont:
  197. ch.send("You cannot put " + ch.see_as(obj) + " into itself.")
  198. # make sure we have enough room
  199. elif obj.weight > cont.container_capacity - cont.weight + cont.weight_raw:
  200. ch.send("There is not enough room in " + ch.see_as(cont) +
  201. " for " + ch.see_as(obj) + ".")
  202. # do the move
  203. else:
  204. obj.container = cont
  205. mud.message(ch, None, obj, cont, True, "to_char", "You put $o in $O.")
  206. mud.message(ch, None, obj, cont, True, "to_room", "$n puts $o in $O.")
  207. def cmd_put(ch, cmd, arg):
  208. '''Usage: put [the] <item> [in the] <container>
  209. Attempts to move an object from your inventory into a specified
  210. container. The container must be in the room, in your inventory, or
  211. worn.'''
  212. try:
  213. found, multi, cont = mud.parse_args(ch, True, cmd, arg,
  214. "[the] obj.inv.multiple " +
  215. "[in] [the] obj.room.inv")
  216. except: return
  217. # make sure we have a container
  218. if not cont.istype("container"):
  219. ch.send(ch.see_as(cont) + " is not a container.")
  220. elif cont.container_is_closed:
  221. ch.send(ch.see_as(cont) + " is currently closed.")
  222. # do we have one or multiple items?
  223. elif multi == False:
  224. do_put(ch, found, cont)
  225. else:
  226. for obj in found:
  227. do_put(ch, obj, cont)
  228. def try_manip_other_exit(room, ex, closed, locked):
  229. '''used by open, close, lock, and unlock. When an exit is manipulated on one
  230. side, it is the case that we'll want to do an identical manipulation on
  231. the other side. That's what we do here. Note: Can only do close OR lock
  232. with one call to this function. Cannot handle both at the same time!'''
  233. opp_dir = None
  234. if ex.dest == None:
  235. return
  236. # see if we can figure out the opposite direction
  237. if ex.opposite != '':
  238. opp_dir = ex.opposite
  239. else:
  240. # figure out the direction of the exit, and its opposite
  241. dirnum = movement.dir_index(room.exdir(ex))
  242. if dirnum != -1:
  243. opp_dir = movement.dir_name[movement.dir_opp[dirnum]]
  244. # do we have an opposite direction to manipulate?
  245. if opp_dir == None:
  246. return
  247. # do we have an opposite exit to manipulate?
  248. opp_ex = ex.dest.exit(opp_dir)
  249. if opp_ex != None:
  250. # figure out our name
  251. name = "an exit"
  252. if opp_ex.name != '':
  253. name = opp_ex.name
  254. # try to manipulate the exit
  255. if closed and not opp_ex.is_closed:
  256. opp_ex.close()
  257. ex.dest.send(name + " closes from the other side.")
  258. elif locked and opp_ex.is_closed and not opp_ex.is_locked:
  259. opp_ex.lock()
  260. ex.dest.send(name + " locks from the other side.")
  261. elif not closed and opp_ex.is_closed and not opp_ex.is_locked:
  262. opp_ex.open()
  263. ex.dest.send(name + " opens from the other side.")
  264. elif not locked and opp_ex.is_locked:
  265. opp_ex.unlock()
  266. ex.dest.send(name + " unlocks from the other side.")
  267. else:
  268. return
  269. # hooks.run("room_change", hooks.build_info("rm", (opp_ex.room, )))
  270. def cmd_lock(ch, cmd, arg):
  271. '''Usage: lock <direction | door | container>
  272. Attempts to lock a specified door, direction, or container.'''
  273. try:
  274. found, type = mud.parse_args(ch, True, cmd, arg,
  275. "[the] {obj.room.inv.eq exit }")
  276. except: return
  277. # what did we find?
  278. if type == "exit":
  279. ex = found
  280. name = ex.name
  281. if ex.name == "":
  282. name = "the exit"
  283. if not ex.is_closed:
  284. ch.send(name + " must be closed first.")
  285. elif ex.is_locked:
  286. ch.send(name + " is already locked.")
  287. elif ex.key == '':
  288. ch.send("You cannot figure out how " + name +" would be locked.")
  289. elif not has_proto(ch, ex.key):
  290. ch.send("You cannot seem to find the key.")
  291. else:
  292. mud.message(ch, None, None, None, True, "to_char",
  293. "You lock " + name + ".")
  294. mud.message(ch, None, None, None, True, "to_room",
  295. "$n locks " + name + ".")
  296. ex.lock()
  297. # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
  298. try_manip_other_exit(ch.room, ex, ex.is_closed, True)
  299. # type must be object
  300. else:
  301. obj = found
  302. if not obj.istype("container"):
  303. ch.send(ch.see_as(obj) + " is not a container.")
  304. elif not obj.container_is_closed:
  305. ch.send(ch.see_as(obj) + " is not closed.")
  306. elif obj.container_is_locked:
  307. ch.send(ch.see_as(obj) + " is already locked.")
  308. elif obj.container_key == '':
  309. ch.send("You cannot figure out how to lock " + ch.see_as(obj))
  310. elif not has_proto(ch, obj.container_key):
  311. ch.send("You cannot seem to find the key.")
  312. else:
  313. mud.message(ch, None, obj, None, True, "to_char", "You lock $o.")
  314. mud.message(ch, None, obj, None, True, "to_room", "$n locks $o.")
  315. obj.container_is_locked = True
  316. def cmd_unlock(ch, cmd, arg):
  317. '''Usage: unlock <door | direction | container>
  318. Attempts to unlock the specified door, direction, or container.'''
  319. try:
  320. found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
  321. except: return
  322. # what did we find?
  323. if type == "exit":
  324. ex = found
  325. name = ex.name
  326. if ex.name == "":
  327. name = "the exit"
  328. if not ex.is_closed:
  329. ch.send(name + " is already open.")
  330. elif not ex.is_locked:
  331. ch.send(name + " is already unlocked.")
  332. elif ex.key == '':
  333. ch.send("You cannot figure out how " + name +
  334. " would be unlocked.")
  335. elif not has_proto(ch, ex.key):
  336. ch.send("You cannot seem to find the key.")
  337. else:
  338. mud.message(ch, None, None, None, True, "to_char",
  339. "You unlock " + name + ".")
  340. mud.message(ch, None, None, None, True, "to_room",
  341. "$n unlocks " + name + ".")
  342. ex.unlock()
  343. # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
  344. try_manip_other_exit(ch.room, ex, ex.is_closed, False)
  345. # must be an object
  346. else:
  347. obj = found
  348. if not obj.istype("container"):
  349. ch.send(ch.see_as(obj) + " is not a container.")
  350. elif not obj.container_is_closed:
  351. ch.send(ch.see_as(obj) + " is already open.")
  352. elif not obj.container_is_locked:
  353. ch.send(ch.see_as(obj) + " is already unlocked.")
  354. elif obj.container_key == '':
  355. ch.send("You cannot figure out how to unlock "+ ch.see_as(obj))
  356. elif not has_proto(ch, obj.container_key):
  357. ch.send("You cannot seem to find the key.")
  358. else:
  359. mud.message(ch, None, obj, None, True, "to_char", "You unlock $o.")
  360. mud.message(ch, None, obj, None, True, "to_room", "$n unlocks $o.")
  361. obj.container_is_locked = False
  362. def cmd_open(ch, cmd, arg):
  363. '''Usage: open [the] <direction | door | container>
  364. Attempts to open the speficied door, direction, or container.'''
  365. try:
  366. found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
  367. except: return
  368. # is it an exit?
  369. if type == "exit":
  370. ex = found
  371. name = ex.name
  372. if name == "":
  373. name = "the exit"
  374. if not ex.is_closed:
  375. ch.send(name + " is already open.")
  376. elif ex.is_locked:
  377. ch.send(name + " must be unlocked first.")
  378. elif not ex.is_closable:
  379. ch.send(name + " cannot be opened.")
  380. else:
  381. mud.message(ch, None, None, None, True, "to_char",
  382. "You open " + name + ".")
  383. mud.message(ch, None, None, None, True, "to_room",
  384. "$n opens " + name + ".")
  385. ex.open()
  386. # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
  387. try_manip_other_exit(ch.room, ex, False, ex.is_locked)
  388. hooks.run("open_door", hooks.build_info("ch ex", (ch, ex)))
  389. # must be an object
  390. else:
  391. obj = found
  392. if not obj.istype("container"):
  393. ch.send(ch.see_as(obj) + " is not a container.")
  394. elif not obj.container_is_closed:
  395. ch.send(ch.see_as(obj) + " is already open.")
  396. elif obj.container_is_locked:
  397. ch.send(ch.see_as(obj) + " must be unlocked first.")
  398. elif not obj.container_is_closable:
  399. ch.send(ch.see_as(obj) + " cannot be opened.")
  400. else:
  401. mud.message(ch, None, obj, None, True, "to_char", "You open $o.")
  402. mud.message(ch, None, obj, None, True, "to_room", "$n opens $o.")
  403. obj.container_is_closed = False
  404. hooks.run("open_obj", hooks.build_info("ch obj", (ch, obj)))
  405. def cmd_close(ch, cmd, arg):
  406. '''Usage: close <direction | door | container>
  407. Attempts to close the specified door, direction, or container.'''
  408. try:
  409. found,type=mud.parse_args(ch,True,cmd,arg, "[the] {obj.room.inv exit }")
  410. except: return
  411. # is it an exit?
  412. if type == "exit":
  413. ex = found
  414. name = ex.name
  415. if name == "":
  416. name = "the exit"
  417. if ex.is_closed:
  418. ch.send(name + " is already closed.")
  419. elif ex.is_locked:
  420. ch.send(name + " must be unlocked first.")
  421. elif not ex.is_closable:
  422. ch.send(name + " cannot be closed.")
  423. else:
  424. mud.message(ch, None, None, None, True, "to_char",
  425. "You close " + name + ".")
  426. mud.message(ch, None, None, None, True, "to_room",
  427. "$n closes " + name + ".")
  428. ex.close()
  429. # hooks.run("room_change", hooks.build_info("rm", (ch.room, )))
  430. try_manip_other_exit(ch.room, ex, True, ex.is_locked)
  431. hooks.run("open_door", hooks.build_info("ch ex", (ch, ex)))
  432. # must be an object
  433. else:
  434. obj = found
  435. if not obj.istype("container"):
  436. ch.send(ch.see_as(obj) + " is not a container.")
  437. elif obj.container_is_closed:
  438. ch.send(ch.see_as(obj) + " is already closed.")
  439. elif not obj.container_is_closable:
  440. ch.send(ch.see_as(obj) + " cannot be closed.")
  441. else:
  442. mud.message(ch, None, obj, None, True, "to_char", "You close $o.")
  443. mud.message(ch, None, obj, None, True, "to_room", "$n closes $o.")
  444. obj.container_is_closed = True
  445. hooks.run("close_obj", hooks.build_info("ch obj", (ch, obj)))
  446. ################################################################################
  447. # load all of our commands
  448. ################################################################################
  449. mudsys.add_cmd("give", None, cmd_give, "player", True)
  450. mudsys.add_cmd("get", None, cmd_get, "player", True)
  451. mudsys.add_cmd("drop", None, cmd_drop, "player", True)
  452. mudsys.add_cmd("remove", None, cmd_remove, "player", True)
  453. mudsys.add_cmd("wear", None, cmd_wear, "player", True)
  454. mudsys.add_cmd("put", None, cmd_put, "player", True)
  455. mudsys.add_cmd("open", None, cmd_open, "player", True)
  456. mudsys.add_cmd("close", None, cmd_close, "player", True)
  457. mudsys.add_cmd("lock", None, cmd_lock, "player", True)
  458. mudsys.add_cmd("unlock", None, cmd_unlock, "player", True)
  459. def chk_can_manip(ch, cmd):
  460. if not ch.pos in ["sitting", "standing", "flying"]:
  461. ch.send("You cannot do that while " + ch.pos + ".")
  462. return False
  463. for cmd in ["give", "get", "drop", "remove", "wear", "put", "open", "close",
  464. "lock", "unlock"]:
  465. mudsys.add_cmd_check(cmd, chk_can_manip)