ask.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811
  1. package server
  2. /* This file contains dialog helpers for the client. */
  3. // import "github.com/beoran/woe/monolog"
  4. import t "github.com/beoran/woe/telnet"
  5. import "github.com/beoran/woe/telnet"
  6. import "github.com/beoran/woe/world"
  7. import "github.com/beoran/woe/monolog"
  8. import "bytes"
  9. import "strings"
  10. import "regexp"
  11. // import "fmt"
  12. import "strconv"
  13. // import "strings"
  14. const NEW_CHARACTER_PRICE = 4
  15. // Switches to "password" mode.
  16. func (me * Client) PasswordMode() telnet.Event {
  17. // The server sends "IAC WILL ECHO", meaning "I, the server, will do any
  18. // echoing from now on." The client should acknowledge this with an IAC DO
  19. // ECHO, and then stop putting echoed text in the input buffer.
  20. // It should also do whatever is appropriate for password entry to the input
  21. // box thing - for example, it might * it out. Text entered in server-echoes
  22. // mode should also not be placed any command history.
  23. // don't use the Q state machne for echos
  24. me.telnet.TelnetSendBytes(t.TELNET_IAC, t.TELNET_WILL, t.TELNET_TELOPT_ECHO)
  25. tev, _, _:= me.TryReadEvent(100)
  26. if tev != nil && !telnet.IsEventType(tev, t.TELNET_DO_EVENT) {
  27. return tev
  28. }
  29. return nil
  30. }
  31. // Switches to "normal, or non-password mode.
  32. func (me * Client) NormalMode() telnet.Event {
  33. // When the server wants the client to start local echoing again, it s}s
  34. // "IAC WONT ECHO" - the client must respond to this with "IAC DONT ECHO".
  35. // Again don't use Q state machine.
  36. me.telnet.TelnetSendBytes(t.TELNET_IAC, t.TELNET_WONT, t.TELNET_TELOPT_ECHO)
  37. tev, _, _ := me.TryReadEvent(100)
  38. if tev != nil && !telnet.IsEventType(tev, t.TELNET_DONT_EVENT) {
  39. return tev
  40. }
  41. return nil
  42. }
  43. func (me * Client) Printf(format string, args ...interface{}) {
  44. me.telnet.TelnetPrintf(format, args...)
  45. }
  46. func (me * Client) ColorTest() {
  47. me.Printf("\033[1mBold\033[0m\r\n")
  48. me.Printf("\033[3mItalic\033[0m\r\n")
  49. me.Printf("\033[4mUnderline\033[0m\r\n")
  50. for fg := 30; fg < 38; fg++ {
  51. me.Printf("\033[%dmForeground Color %d\033[0m\r\n", fg, fg)
  52. me.Printf("\033[1;%dmBold Foreground Color %d\033[0m\r\n", fg, fg)
  53. }
  54. for bg := 40; bg < 48; bg++ {
  55. me.Printf("\033[%dmBackground Color %d\033[0m\r\n", bg, bg)
  56. me.Printf("\033[1;%dmBold Background Color %d\033[0m\r\n", bg, bg)
  57. }
  58. }
  59. // Blockingly reads a single command from the client
  60. func (me * Client) ReadCommand() (something []byte) {
  61. something = nil
  62. for something == nil {
  63. something, _, _ = me.TryRead(-1)
  64. if something != nil {
  65. something = bytes.TrimRight(something, "\r\n")
  66. return something
  67. }
  68. }
  69. return nil
  70. }
  71. func (me * Client) AskSomething(prompt string, re string, nomatch_prompt string, noecho bool) (something []byte) {
  72. something = nil
  73. if noecho {
  74. me.PasswordMode()
  75. }
  76. for something == nil || len(something) == 0 {
  77. me.Printf("%s", prompt)
  78. something, _, _ = me.TryRead(-1)
  79. if something != nil {
  80. something = bytes.TrimRight(something, "\r\n")
  81. if len(re) > 0 {
  82. ok, _ := regexp.Match(re, something)
  83. if !ok {
  84. me.Printf("\n%s\n", nomatch_prompt)
  85. something = nil
  86. }
  87. }
  88. }
  89. }
  90. if noecho {
  91. me.NormalMode()
  92. me.Printf("\n")
  93. }
  94. return something
  95. }
  96. func (me * Client) AskYesNo(prompt string) bool {
  97. res := me.AskSomething(prompt + " (y/n)","[ynYN]", "Please answer y or n.", false)
  98. if res[0] == 'Y'|| res[0] == 'y' {
  99. return true
  100. } else {
  101. return false
  102. }
  103. }
  104. // Interface for an item in a list of options.
  105. type AskOption interface {
  106. // Name of the option, also used to compare input
  107. AskName() string
  108. // Short description of the option, shown after name
  109. AskShort() string
  110. // Long description, displayed if "help name" is requested
  111. AskLong() string
  112. // Accound privilege required or the option to be selectable.
  113. AskPrivilege() world.Privilege
  114. }
  115. type AskOptionList interface {
  116. AskOptionListLen() int
  117. AskOptionListGet(index int) AskOption
  118. }
  119. type TrivialAskOption string
  120. func (me TrivialAskOption) AskName() (string) {
  121. return string(me)
  122. }
  123. func (me TrivialAskOption) AskLong() (string) {
  124. return ""
  125. }
  126. func (me TrivialAskOption) AskShort() (string) {
  127. return ""
  128. }
  129. func (me TrivialAskOption) AskPrivilege() (world.Privilege) {
  130. return world.PRIVILEGE_ZERO
  131. }
  132. type TrivialAskOptionList []TrivialAskOption
  133. func (me TrivialAskOptionList) AskOptionListLen() int {
  134. return len(me)
  135. }
  136. func (me TrivialAskOptionList) AskOptionListGet(index int) AskOption {
  137. return me[index]
  138. }
  139. type SimpleAskOption struct {
  140. Name string
  141. Short string
  142. Long string
  143. Privilege world.Privilege
  144. }
  145. func (me SimpleAskOption) AskName() string {
  146. return me.Name
  147. }
  148. func (me SimpleAskOption) AskShort() string {
  149. return me.Short
  150. }
  151. func (me SimpleAskOption) AskLong() string {
  152. return me.Long
  153. }
  154. func (me SimpleAskOption) AskPrivilege() world.Privilege {
  155. return me.Privilege
  156. }
  157. type SimpleAskOptionList []SimpleAskOption
  158. func (me SimpleAskOptionList) AskOptionListLen() int {
  159. return len(me)
  160. }
  161. func (me SimpleAskOptionList) AskOptionListGet(index int) AskOption {
  162. return me[index]
  163. }
  164. type JobListAsker []world.Job
  165. func (me JobListAsker) AskOptionListLen() int {
  166. return len(me)
  167. }
  168. func (me JobListAsker) AskOptionListGet(index int) AskOption {
  169. return me[index]
  170. }
  171. type KinListAsker []world.Kin
  172. func (me KinListAsker) AskOptionListLen() int {
  173. return len(me)
  174. }
  175. func (me KinListAsker) AskOptionListGet(index int) AskOption {
  176. return me[index]
  177. }
  178. type GenderListAsker []world.Gender
  179. func (me GenderListAsker) AskOptionListLen() int {
  180. return len(me)
  181. }
  182. func (me GenderListAsker) AskOptionListGet(index int) AskOption {
  183. return me[index]
  184. }
  185. type AskOptionSlice []AskOption
  186. type AskOptionFilterFunc func(AskOption) (AskOption)
  187. func (me AskOptionSlice) AskOptionListLen() int {
  188. return len(me)
  189. }
  190. func (me AskOptionSlice) AskOptionListGet(index int) AskOption {
  191. return me[index]
  192. }
  193. func AskOptionListEach(me AskOptionList, cb AskOptionFilterFunc) (AskOption) {
  194. for i := 0; i < me.AskOptionListLen() ; i++ {
  195. res := cb(me.AskOptionListGet(i))
  196. if (res != nil) {
  197. return res
  198. }
  199. }
  200. return nil
  201. }
  202. func AskOptionListFilter(me AskOptionList, cb AskOptionFilterFunc) (AskOptionList) {
  203. result := make(AskOptionSlice, 0)
  204. for i := 0; i < me.AskOptionListLen() ; i++ {
  205. res := cb(me.AskOptionListGet(i))
  206. if (res != nil) {
  207. result = append(result, res)
  208. }
  209. }
  210. return result
  211. }
  212. /* Finds the name irrespecful of the case */
  213. func AskOptionListFindName(me AskOptionList, name string) (AskOption) {
  214. return AskOptionListEach(me, func (e AskOption) (AskOption) {
  215. if strings.ToLower(e.AskName()) == strings.ToLower(name) {
  216. return e
  217. } else {
  218. return nil
  219. }
  220. })
  221. }
  222. /* Filters the list by privilege level (only those allowed by the level are retained) */
  223. func AskOptionListFilterPrivilege(me AskOptionList, privilege world.Privilege) (AskOptionList) {
  224. return AskOptionListFilter(me, func (e AskOption) (AskOption) {
  225. if (e.AskPrivilege() <= privilege) {
  226. return e
  227. } else {
  228. return nil
  229. }
  230. })
  231. }
  232. type MergedAskOptionList struct {
  233. head AskOptionList
  234. tail AskOptionList
  235. }
  236. func (me * MergedAskOptionList) AskOptionListLen() int {
  237. return me.head.AskOptionListLen() + me.tail.AskOptionListLen()
  238. }
  239. func (me * MergedAskOptionList) AskOptionListGet(index int) (AskOption) {
  240. headlen := me.head.AskOptionListLen()
  241. if (index < headlen) {
  242. return me.head.AskOptionListGet(index)
  243. }
  244. return me.tail.AskOptionListGet(index - headlen)
  245. }
  246. /* Merges two AskOptionLists without copying using the MergedAskOptionList rtype */
  247. func AskOptionListMerge(me AskOptionList, you AskOptionList) (AskOptionList) {
  248. return &MergedAskOptionList{me, you}
  249. }
  250. func (me AskOptionSlice) Each(cb AskOptionFilterFunc) (AskOption) {
  251. for i := 0; i < len(me) ; i++ {
  252. res := cb(me[i])
  253. if (res != nil) {
  254. return res
  255. }
  256. }
  257. return nil
  258. }
  259. func (me AskOptionSlice) Filter(cb AskOptionFilterFunc) (AskOptionSlice) {
  260. result := make(AskOptionSlice, 0)
  261. for i := 0; i < len(me) ; i++ {
  262. res := cb(me[i])
  263. if (res != nil) {
  264. result = append(result, res)
  265. }
  266. }
  267. return result
  268. }
  269. /* Finds the name irrespecful of the case */
  270. func (me AskOptionSlice) FindName(name string) (AskOption) {
  271. return me.Each(func (e AskOption) (AskOption) {
  272. if strings.ToLower(e.AskName()) == strings.ToLower(name) {
  273. return e
  274. } else {
  275. return nil
  276. }
  277. })
  278. }
  279. /* Filters the list by privilege level (only those allowed by the level are retained) */
  280. func (me AskOptionSlice) FilterPrivilege(privilege world.Privilege) (AskOptionSlice) {
  281. return me.Filter(func (e AskOption) (AskOption) {
  282. if (e.AskPrivilege() <= privilege) {
  283. return e
  284. } else {
  285. return nil
  286. }
  287. })
  288. }
  289. func (me * Client) AskOptionListHelp(alist AskOptionList, input []byte) {
  290. re := regexp.MustCompile("[^ \t,]+")
  291. argv := re.FindAll(input, -1)
  292. if (len(argv) < 2) {
  293. me.Printf("Help usage: help <topic>.\n")
  294. return
  295. }
  296. e := AskOptionListFindName(alist, string(argv[1]))
  297. if (e == nil) {
  298. me.Printf("Cannot find topic %s in list. No help available.\n", string(argv[1]))
  299. } else {
  300. al := e.AskLong()
  301. if (al == "") {
  302. me.Printf("Topic %s found, but help is unavailable.\n", string(argv[1]))
  303. } else {
  304. me.Printf("Help on %s:\n%s\n", string(argv[1]), e.AskLong())
  305. }
  306. }
  307. }
  308. func (me * Client) AskOptionListOnce(heading string, prompt string, noecho bool, alist AskOptionList) (result AskOption) {
  309. list := AskOptionListFilterPrivilege(alist, me.account.Privilege)
  310. me.Printf("\n%s\n\n",heading)
  311. for i := 0; i < list.AskOptionListLen(); i++ {
  312. v := list.AskOptionListGet(i)
  313. sh := v.AskShort()
  314. if sh == "" {
  315. me.Printf("[%d] %s\n", i+1, v.AskName())
  316. } else {
  317. me.Printf("[%d] %s: %s\n", i+1, v.AskName(), sh)
  318. }
  319. }
  320. me.Printf("\n")
  321. aid := me.AskSomething(prompt, "", "", false);
  322. iresp, err := strconv.Atoi(string(aid))
  323. if err != nil { /* Try by name if not a number. */
  324. e := AskOptionListFindName(alist, string(aid))
  325. if e != nil {
  326. return e
  327. } else if ok, _ := regexp.Match("help", bytes.ToLower(aid)) ; ok {
  328. me.AskOptionListHelp(list, aid)
  329. } else {
  330. me.Printf("Name not found in list. Please choose a number or name from the list above. Or type help <option> for help on that option.\n")
  331. }
  332. } else if (iresp>0) && (iresp<=list.AskOptionListLen()) {
  333. /* In range of list. */
  334. return list.AskOptionListGet(iresp-1)
  335. } else {
  336. me.Printf("Please choose a number or name from the list above.\n")
  337. }
  338. return nil
  339. }
  340. func (me * Client) AskOptionList(
  341. heading string, prompt string, noecho bool,
  342. noconfirm bool, list AskOptionList) (result AskOption) {
  343. for {
  344. result = me.AskOptionListOnce(heading, prompt, noecho, list)
  345. if result != nil {
  346. if noconfirm || me.AskYesNo(heading + "\nConfirm " + result.AskName() + "? ") {
  347. return result
  348. }
  349. }
  350. }
  351. }
  352. func (me * Client) AskOptionListExtra(heading string,
  353. prompt string, noecho bool, noconfirm bool, list AskOptionList,
  354. extra AskOptionList) (result AskOption) {
  355. xlist := AskOptionListMerge(list, extra)
  356. return me.AskOptionList(heading, prompt, noecho, noconfirm, xlist)
  357. }
  358. func (me * Client) AskEntityListOnce(
  359. heading string, prompt string, noecho bool,
  360. elist world.EntitylikeSlice, extras []string) (result world.Entitylike, alternative string) {
  361. list := elist.FilterPrivilege(me.account.Privilege)
  362. me.Printf("\n%s\n\n",heading)
  363. last := 0
  364. for i, v := range(list) {
  365. e := v.AsEntity()
  366. me.Printf("[%d] %s: %s\n", i+1, e.Name, e.Short)
  367. last = i+1
  368. }
  369. if extras != nil {
  370. for i, v := range(extras) {
  371. me.Printf("[%d] %s\n", last+i+1, v)
  372. }
  373. }
  374. me.Printf("\n")
  375. aid := me.AskSomething(prompt, "", "", false);
  376. iresp, err := strconv.Atoi(string(aid))
  377. if err != nil { /* Try by name if not a number. */
  378. e := list.FindName(string(aid))
  379. if e != nil {
  380. return e, ""
  381. } else {
  382. if extras != nil {
  383. for _, v := range(extras) {
  384. if strings.ToLower(v) == strings.ToLower(string(aid)) {
  385. return nil, v
  386. }
  387. }
  388. }
  389. me.Printf("Name not found in list. Please choose a number or name from the list above.\n")
  390. }
  391. } else if (iresp>0) && (iresp<=len(list)) { /* In range of list. */
  392. return list[iresp-1], ""
  393. } else if (extras != nil) && (iresp>last) && (iresp <= last + len(extras)) {
  394. return nil, extras[iresp - last - 1]
  395. } else {
  396. me.Printf("Please choose a number or name from the list above.\n")
  397. }
  398. return nil, ""
  399. }
  400. func (me * Client) AskEntityList(
  401. heading string, prompt string, noecho bool,
  402. noconfirm bool, list world.EntitylikeSlice, extras []string) (result world.Entitylike, alternative string) {
  403. for {
  404. result, alternative = me.AskEntityListOnce(heading, prompt, noecho, list, extras)
  405. if result != nil {
  406. e := result.AsEntity()
  407. if (!noconfirm) {
  408. me.Printf("\n%s: %s\n\n%s\n\n", e.Name, e.Short, e.Long)
  409. }
  410. if noconfirm || me.AskYesNo(heading + "\nConfirm " + e.Name + "? ") {
  411. return result, ""
  412. }
  413. } else if alternative != "" {
  414. if noconfirm || me.AskYesNo("Confirm " + alternative + " ?") {
  415. return result, alternative
  416. }
  417. }
  418. }
  419. }
  420. const LOGIN_RE = "^[A-Za-z][A-Za-z0-9]*$"
  421. func (me * Client) AskLogin() []byte {
  422. return me.AskSomething("Login?>", LOGIN_RE, "Login must consist of letters followed by letters or numbers.", false)
  423. }
  424. const EMAIL_RE = "@"
  425. func (me * Client) AskEmail() []byte {
  426. return me.AskSomething("E-mail?>", EMAIL_RE, "Email must have at least an @ in there somewhere.", false)
  427. }
  428. const CHARNAME_RE = "^[A-Z][A-Za-z]+$"
  429. func (me * Client) AskCharacterName() []byte {
  430. return me.AskSomething("Character Name?>", CHARNAME_RE, "Character name consist of a capital letter followed by at least one letter.", false)
  431. }
  432. func (me * Client) AskPassword() []byte {
  433. return me.AskSomething("Password?>", "", "", true)
  434. }
  435. func (me * Client) AskRepeatPassword() []byte {
  436. return me.AskSomething("Repeat Password?>", "", "", true)
  437. }
  438. func (me * Client) HandleCommand() {
  439. command := me.ReadCommand()
  440. me.ProcessCommand(command)
  441. }
  442. func (me * Client) ExistingAccountDialog() bool {
  443. pass := me.AskPassword()
  444. for pass == nil {
  445. me.Printf("Password may not be empty!\n")
  446. pass = me.AskPassword()
  447. }
  448. if !me.account.Challenge(string(pass)) {
  449. me.Printf("Password not correct!\n")
  450. me.Printf("Disconnecting!\n")
  451. return false
  452. }
  453. return true
  454. }
  455. func (me * Client) NewAccountDialog(login string) bool {
  456. for me.account == nil {
  457. me.Printf("\nWelcome, %s! Creating new account...\n", login)
  458. pass1 := me.AskPassword()
  459. if pass1 == nil {
  460. return false
  461. }
  462. pass2 := me.AskRepeatPassword()
  463. if pass1 == nil {
  464. return false
  465. }
  466. if string(pass1) != string(pass2) {
  467. me.Printf("\nPasswords do not match! Please try again!\n")
  468. continue
  469. }
  470. email := me.AskEmail()
  471. if email == nil { return false }
  472. me.account = world.NewAccount(login, string(pass1), string(email), 7)
  473. err := me.account.Save(me.server.DataPath())
  474. if err != nil {
  475. monolog.Error("Could not save account %s: %v", login, err)
  476. me.Printf("\nFailed to save your account!\nPlease contact a WOE administrator!\n")
  477. return false
  478. }
  479. monolog.Info("Created new account %s", login)
  480. me.Printf("\nSaved your account.\n")
  481. return true
  482. }
  483. return false
  484. }
  485. func (me * Client) AccountDialog() bool {
  486. login := me.AskLogin()
  487. if login == nil { return false }
  488. var err error
  489. if me.server.World.GetAccount(string(login)) != nil {
  490. me.Printf("Account already logged in!\n")
  491. me.Printf("Disconnecting!\n")
  492. return false
  493. }
  494. me.account, err = me.server.World.LoadAccount(string(login))
  495. if err != nil {
  496. monolog.Warning("Could not load account %s: %v", login, err)
  497. }
  498. if me.account != nil {
  499. return me.ExistingAccountDialog()
  500. } else {
  501. return me.NewAccountDialog(string(login))
  502. }
  503. }
  504. func (me * Client) NewCharacterDialog() bool {
  505. noconfirm := true
  506. extra := TrivialAskOptionList { TrivialAskOption("Cancel") }
  507. me.Printf("New character:\n")
  508. charname := me.AskCharacterName()
  509. existing, aname, _ := world.LoadCharacterByName(me.server.DataPath(), string(charname))
  510. for (existing != nil) {
  511. if (aname == me.account.Name) {
  512. me.Printf("You already have a character with a similar name!\n")
  513. } else {
  514. me.Printf("That character name is already taken by someone else.\n")
  515. }
  516. charname := me.AskCharacterName()
  517. existing, aname, _ = world.LoadCharacterByName(me.server.DataPath(), string(charname))
  518. }
  519. kinres := me.AskOptionListExtra("Please choose the kin of this character", "Kin?> ", false, noconfirm, KinListAsker(world.KinList), extra)
  520. if sopt, ok := kinres.(TrivialAskOption) ; ok {
  521. if string(sopt) == "Cancel" {
  522. me.Printf("Character creation canceled.\n")
  523. return true
  524. } else {
  525. return true
  526. }
  527. }
  528. kin := kinres.(world.Kin)
  529. genres := me.AskOptionListExtra("Please choose the gender of this character", "Gender?> ", false, noconfirm, GenderListAsker(world.GenderList), extra)
  530. if sopt, ok := kinres.(TrivialAskOption) ; ok {
  531. if string(sopt) == "Cancel" {
  532. me.Printf("Character creation canceled.\n")
  533. return true
  534. } else {
  535. return true
  536. }
  537. }
  538. gender := genres.(world.Gender)
  539. jobres := me.AskOptionListExtra("Please choose the job of this character", "Gender?> ", false, noconfirm, JobListAsker(world.JobList), extra)
  540. if sopt, ok := kinres.(TrivialAskOption) ; ok {
  541. if string(sopt) == "Cancel" {
  542. me.Printf("Character creation canceled.\n")
  543. return true
  544. } else {
  545. return true
  546. }
  547. }
  548. job := jobres.(world.Job)
  549. character := world.NewCharacter(me.account,
  550. string(charname), &kin, &gender, &job)
  551. me.Printf("%s", character.Being.ToStatus());
  552. ok := me.AskYesNo("Is this character ok?")
  553. if (!ok) {
  554. me.Printf("Character creation canceled.\n")
  555. return true
  556. }
  557. me.account.AddCharacter(character)
  558. me.account.Points -= NEW_CHARACTER_PRICE
  559. me.account.Save(me.server.DataPath())
  560. character.Save(me.server.DataPath())
  561. me.Printf("Character %s saved.\n", character.Being.Name)
  562. return true
  563. }
  564. func (me * Client) DeleteCharacterDialog() (bool) {
  565. extra := []AskOption { TrivialAskOption("Cancel"), TrivialAskOption("Disconnect") }
  566. els := me.AccountCharacterList()
  567. els = append(els, extra...)
  568. result := me.AskOptionList("Character to delete?",
  569. "Character?>", false, false, els)
  570. if alt, ok := result.(TrivialAskOption) ; ok {
  571. if string(alt) == "Disconnect" {
  572. me.Printf("Disconnecting")
  573. return false
  574. } else if string(alt) == "Cancel" {
  575. me.Printf("Canceled")
  576. return true
  577. } else {
  578. monolog.Warning("Internal error, unhandled case.")
  579. return true
  580. }
  581. }
  582. character := result.(*world.Character)
  583. /* A character that is deleted gives NEW_CHARACTER_PRICE +
  584. * level / (NEW_CHARACTER_PRICE * 2) points, but only after the delete. */
  585. np := NEW_CHARACTER_PRICE + character.Level / (NEW_CHARACTER_PRICE * 2)
  586. me.account.DeleteCharacter(me.server.DataPath(), character)
  587. me.account.Points += np
  588. return true
  589. }
  590. func (me * Client) AccountCharacterList() AskOptionSlice {
  591. els := make(AskOptionSlice, 0, 16)
  592. for i:= 0 ; i < me.account.NumCharacters(); i++ {
  593. chara := me.account.GetCharacter(i)
  594. els = append(els, chara)
  595. }
  596. return els
  597. }
  598. func (me * Client) ChooseCharacterDialog() (bool) {
  599. extra := []AskOption {
  600. SimpleAskOption{"New", "Create New character",
  601. "Create a new character. This option costs 4 points.",
  602. world.PRIVILEGE_ZERO},
  603. SimpleAskOption{"Disconnect", "Disconnect from server",
  604. "Disconnect your client from this server.",
  605. world.PRIVILEGE_ZERO},
  606. SimpleAskOption{"Delete", "Delete character",
  607. "Delete a character. A character that has been deleted cannot be reinstated. You will receive point bonuses for deleting your characters that depend on their level.",
  608. world.PRIVILEGE_ZERO},
  609. }
  610. var pchara * world.Character = nil
  611. for pchara == nil {
  612. els := me.AccountCharacterList()
  613. els = append(els, extra...)
  614. result := me.AskOptionList("Choose a character?", "Character?>", false, true, els)
  615. switch opt := result.(type) {
  616. case SimpleAskOption:
  617. if (opt.Name == "New") {
  618. if (me.account.Points >= NEW_CHARACTER_PRICE) {
  619. if (!me.NewCharacterDialog()) {
  620. return false
  621. }
  622. } else {
  623. me.Printf("Sorry, you have no points left to make new characters!\n")
  624. }
  625. } else if opt.Name == "Disconnect" {
  626. me.Printf("Disconnecting\n")
  627. return false
  628. } else if opt.Name == "Delete" {
  629. if (!me.DeleteCharacterDialog()) {
  630. return false
  631. }
  632. } else {
  633. me.Printf("Internal error, alt not valid: %v.", opt)
  634. }
  635. case * world.Character:
  636. pchara = opt
  637. default:
  638. me.Printf("What???")
  639. }
  640. me.Printf("You have %d points left.\n", me.account.Points)
  641. }
  642. me.character = pchara
  643. me.Printf("%s\n", me.character.Being.ToStatus())
  644. me.Printf("Welcome, %s!\n", me.character.Name)
  645. return true
  646. }
  647. func (me * Client) CharacterDialog() bool {
  648. me.Printf("You have %d remaining points.\n", me.account.Points)
  649. for me.account.NumCharacters() < 1 {
  650. me.Printf("You have no characters yet!\n")
  651. if (me.account.Points >= NEW_CHARACTER_PRICE) {
  652. if (!me.NewCharacterDialog()) {
  653. return false
  654. }
  655. } else {
  656. me.Printf("Sorry, you have no characters, and no points left to make new characters!\n")
  657. me.Printf("Please contact the staff of WOE if you think this is a mistake.\n")
  658. me.Printf("Disconnecting!\n")
  659. return false
  660. }
  661. }
  662. return me.ChooseCharacterDialog()
  663. }