public
Fork of sykopomp/sykosomatic
Description: Sykopomp's Somewhat Masterful Text in Console (MUD engine)
Homepage: http://sykosomatic.org
Clone URL: git://github.com/Ramarren/sykosomatic.git
sykosomatic / account.lisp
100644 214 lines (189 sloc) 7.192 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
;; Copyright 2008 Josh Marchan
 
;; This file is part of sykosomatic
 
;; sykosomatic is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
 
;; sykosomatic is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
 
;; You should have received a copy of the GNU General Public License
;; along with sykosomatic. If not, see <http://www.gnu.org/licenses/>.
 
;; account.lisp
;;
;; This file contains the <account> class, meant to hold some basic information about user accounts
;; like login/pass, characters available, and the client currently connected to the account. This
;; file also contains the functions that handle user login, account creation, and account management.
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(in-package :sykosomatic)
 
;;;
;;; Account vars
;;;
 
(defvar *accounts* (make-hash-table :test #'equalp)
  "Hash table holding all existing accounts.")
 
(defvar *max-account-id* 0)
 
;;;
;;; Account class
;;;
(defclass <account> ()
  ((username
    :initarg :username
    :reader username)
   (password
    :initarg :password
    :accessor password)
   (id
    :initform (incf *max-account-id*)
    :reader id
    :documentation "Unique account ID number.")
   (avatars
    :accessor avatars
    :initform nil
    :documentation "Characters belonging to this account.")
   (client
    :accessor client
    :initform nil
    :documentation "Client currently associated with this account.")
   (account-type
    :accessor account-type
    :initarg :account-type
    :initform nil
    :documentation "The type of account. Used to determine access levels.")
   (known-ips
    :initarg :known-ips
    :accessor know-ips
    :initform nil
    :documentation "All IPs this account has been known no use.")))
 
(defun make-account (&key username password)
  "Generic constructor"
  (make-instance '<account> :username username :password password))
 
;;;
;;; Account Login
;;;
 
(defun get-account-by-name (username)
  "Fetches an account using a username."
  (find username *accounts* :key #'string-equal))
 
;;Note: (if .. (progn ..)) should be replaced by (when .. forms*)
(defun login-client (client)
  "Logs a user into their account"
  (let ((account (validate-login client (prompt-username client))))
    (if account
(progn
(setf (account client) account)
(setf (client account) client)
(pushnew (ip client) (know-ips account))
(account-menu client)))))
 
(defun prompt-username (client)
  "Prompts a client for a username, returns a valid account."
  (let* ((account-name (prompt-client client "~%Username: "))
(account (get-account-by-name account-name)))
    (if account
account
(progn
(write-to-client client "~&Invalid username, please try again.")
(prompt-username client)))))
 
(defun validate-login (client account)
  "Prompts the user for a password, and validates the login."
  (let ((password (prompt-client client "~&Password: ")))
    (if (equal password (password account))
account
(validate-login client account))))
 
(defun account-menu (client)
  "Simple selection menu that new clients once they've logged into an account."
  (write-to-client client "~&Choose your destiny: ~%")
  (write-to-client client "-----------------------~%")
  (write-to-client client "1. Create a new character~%")
  (write-to-client client "2. Enter existing character~%")
  (write-to-client client "-----------------------~%~%")
  (let ((choice (prompt-client client "Your choice: ")))
    (cond ((string-equal choice "1")
(create-an-avatar client))
((string-equal choice "2")
(choose-avatar client))
(t
(progn
(write-to-client client "~&Invalid choice.")
(account-menu client))))))
 
(defun create-an-avatar (client)
  "Takes user through the avatar-creation process."
  (let ((account (account client)))
    (let* ((avatar-name (prompt-client client "~&Choose a name for your character: "))
(avatar (make-player
:name avatar-name
:desc "generic description"
:desc-long "generic long-description")))
      (pushnew avatar *players*)
      (pushnew avatar (avatars account)))))
 
(defun choose-avatar (client)
  "Lets a player choose an existing avatar to play on."
  (print-available-avatars client)
  (let* ((avatars (avatars (account client)))
(avatar-choice (prompt-client client "~%~%Choose your destiny: "))
(avatar (find avatar-choice avatars :test #'string-equal)))
    (if avatar
(progn
(setf (avatar client) avatar)
(player-main-loop client))
(progn
(write-to-client client "~&No such character, please try again.~%")
(choose-avatar client)))))
 
(defun print-available-avatars (client)
  "Prints a list of available avatars."
  (let ((avatars (avatars (account client))))
    (write-to-client client "~%Characters:~%-----------~%~%")
    (loop for avatar in avatars
       do (write-to-client client "~&~a~&" (name avatar)))))
 
 
;;;
;;; Account Creation
;;;
 
;; TODO
(defun setup-account (username)
  (format *query-io* "Welcome to BMUD new player.~%")
  (format *query-io* "I'm going to need to ask you some questions to make your account.~%")
  (multiple-value-bind (firstname lastname) (setup-name)
    (let ((email (setup-email))
(username (setup-username username))
(password (setup-password)))
      (values username password firstname lastname email))))
;; TODO
(defun setup-name ()
  "blegh. Cleaning up shittier code than mine :-\ "
  (let ((firstname (prompt-read "Please enter your first name"))
(lastname (prompt-read "Please enter your first name")))
    (if (y-or-n-p "Greetings ~a ~a. Is this name correct" firstname lastname)
(values firstname lastname)
(setup-name))))
;; TODO
(defun setup-email ()
  "cleaned-up e-mail setup without the suck."
  (let ((email (prompt-read "Please enter your email address")))
    (if (cl-ppcre:scan "^[\\w._%\\-]+@[\\w.\\-]+\\.([A-Za-z]{2}|com|edu|org|net|biz|info|name|aero|biz|info|jobs|museum|name)$" email)
(if (y-or-n-p "Is the email address ~a correct?" email)
email
(setup-email))
(progn
(format *query-io* "I'm sorry, ~a is not a valid email address.~%" email)
(setup-email)))))
;; TODO
(defun setup-username (username)
  "Setup the user's username."
  (format *query-io* "It seems that you chose username ~a.~%" username)
  (if (y-or-n-p "Would you like to use this username?")
      username
      (let ((username (prompt-read "Please enter your desired username")))
(setup-username username))))
;; TODO
(defun setup-password ()
  "Allow the user to choose a password."
  (let* ((password (prompt-read "Please choose a password"))
(pass-confirm (prompt-read "Please retype the password")))
    (if (equal password pass-confirm)
password
(progn
(format *query-io* "~%Passwords did not match, trying again.~%")
(setup-password)))))
 
;;;
;;; Account Management
;;;