classless_mud 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +32 -0
- data/Rakefile +5 -0
- data/bin/classless_mud +11 -0
- data/classless_mud.gemspec +29 -0
- data/conf/settings.yml +4 -0
- data/lib/classless_mud.rb +72 -0
- data/lib/classless_mud/account_builder.rb +81 -0
- data/lib/classless_mud/character.rb +39 -0
- data/lib/classless_mud/character_sheet.rb +26 -0
- data/lib/classless_mud/character_sheet_builder.rb +72 -0
- data/lib/classless_mud/client.rb +47 -0
- data/lib/classless_mud/colorizer.rb +33 -0
- data/lib/classless_mud/commands.rb +32 -0
- data/lib/classless_mud/commands/admin/kick.rb +15 -0
- data/lib/classless_mud/commands/bad_command.rb +81 -0
- data/lib/classless_mud/commands/character.rb +9 -0
- data/lib/classless_mud/commands/chat.rb +14 -0
- data/lib/classless_mud/commands/commands.rb +31 -0
- data/lib/classless_mud/commands/dance.rb +20 -0
- data/lib/classless_mud/commands/eat.rb +26 -0
- data/lib/classless_mud/commands/get.rb +20 -0
- data/lib/classless_mud/commands/inventory.rb +12 -0
- data/lib/classless_mud/commands/look.rb +43 -0
- data/lib/classless_mud/commands/move.rb +16 -0
- data/lib/classless_mud/commands/quit.rb +16 -0
- data/lib/classless_mud/commands/say.rb +10 -0
- data/lib/classless_mud/commands/score.rb +12 -0
- data/lib/classless_mud/commands/whisper.rb +17 -0
- data/lib/classless_mud/commands/who.rb +9 -0
- data/lib/classless_mud/effect.rb +14 -0
- data/lib/classless_mud/exit.rb +15 -0
- data/lib/classless_mud/game.rb +40 -0
- data/lib/classless_mud/game_master.rb +12 -0
- data/lib/classless_mud/input_parser.rb +7 -0
- data/lib/classless_mud/item.rb +21 -0
- data/lib/classless_mud/npc.rb +12 -0
- data/lib/classless_mud/player.rb +57 -0
- data/lib/classless_mud/room.rb +60 -0
- data/lib/classless_mud/server.rb +18 -0
- data/lib/classless_mud/version.rb +3 -0
- data/lib/classless_mud/world.rb +26 -0
- data/tasks/db.rake +10 -0
- metadata +202 -0
@@ -0,0 +1,47 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
MOTD = <<EOS
|
3
|
+
.-~~~~~~~~~-._ _.-~~~~~~~~~-.
|
4
|
+
__.' ~. .~ `.__
|
5
|
+
.'// We are \./ awesome. \\`.
|
6
|
+
.'// | \\`.
|
7
|
+
.'// .-~"""""""~~~~-._ | _,-~~~~"""""""~-. \\`.
|
8
|
+
.'//.-" `-. | .-' "-.\\`.
|
9
|
+
.'//______.============-.. \ | / ..-============.______\\`.
|
10
|
+
.'______________________________\|/______________________________`.
|
11
|
+
EOS
|
12
|
+
|
13
|
+
class Client < EventMachine::Connection
|
14
|
+
attr_reader :player
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
@callbacks = []
|
18
|
+
end
|
19
|
+
|
20
|
+
def start game
|
21
|
+
@game = game
|
22
|
+
send_data MOTD
|
23
|
+
::ClasslessMud::AccountBuilder.create(self, game) { |player|
|
24
|
+
@player = player
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def receive_data data
|
29
|
+
data = data.chomp
|
30
|
+
if @callbacks.any?
|
31
|
+
callback = @callbacks.pop
|
32
|
+
callback.call(data)
|
33
|
+
else
|
34
|
+
player.handle_message(data)
|
35
|
+
end
|
36
|
+
player.display_prompt if player
|
37
|
+
end
|
38
|
+
|
39
|
+
def on &callback
|
40
|
+
@callbacks.push callback
|
41
|
+
end
|
42
|
+
|
43
|
+
def puts message
|
44
|
+
send_data "#{message}\n"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Colorizer
|
3
|
+
# To add more, look at this
|
4
|
+
# alias colortest="python -c \"print('\n'.join([(' '.join([('\033[38;5;' + str((i + j)) + 'm' + str((i + j)).ljust(5) + '\033[0m') if i + j < 256 else '' for j in range(10)])) for i in range(0, 256, 10)]))\""
|
5
|
+
CODES = {
|
6
|
+
red: '38;5;1',
|
7
|
+
green: '38;5;2',
|
8
|
+
yellow: '38;5;3',
|
9
|
+
blue: '38;5;4',
|
10
|
+
purple: '38;5;5',
|
11
|
+
teal: '38;5;7',
|
12
|
+
white: '38;5;8',
|
13
|
+
black: '38;5;16',
|
14
|
+
bright_blue: '38;5;27',
|
15
|
+
grey: '38;5;59',
|
16
|
+
bright_teal: '38;5;81',
|
17
|
+
bright_green: '38;5;83',
|
18
|
+
bright_red: '38;5;160',
|
19
|
+
bright_white: '38;5;195',
|
20
|
+
bright_yellow: '38;5;226',
|
21
|
+
bright_purple: '38;5;207',
|
22
|
+
}
|
23
|
+
|
24
|
+
def colorize(input, color)
|
25
|
+
color_code = CODES[color]
|
26
|
+
"\e[#{color_code}m#{input}\e[0m"
|
27
|
+
end
|
28
|
+
|
29
|
+
CODES.keys.each do |color|
|
30
|
+
define_method(color) { |input| colorize(input, color) }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
ALIASES_TO_COMMANDS_MAP = {
|
4
|
+
'north' => Move,
|
5
|
+
'west' => Move,
|
6
|
+
'south' => Move,
|
7
|
+
'east' => Move
|
8
|
+
}
|
9
|
+
|
10
|
+
def self.parse data
|
11
|
+
command = data.split[0]
|
12
|
+
return ALIASES_TO_COMMANDS_MAP[command] if ALIASES_TO_COMMANDS_MAP.has_key?(command)
|
13
|
+
all_commands.detect(-> { BadCommand }) { |c| c.name.demodulize.to_s.downcase == command }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.all_commands
|
17
|
+
regular_commands + admin_commands
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.regular_commands
|
21
|
+
ClasslessMud::Commands.constants
|
22
|
+
.select { |c| Class === ClasslessMud::Commands.const_get(c) }
|
23
|
+
.map { |c| ClasslessMud::Commands.const_get(c) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.admin_commands
|
27
|
+
ClasslessMud::Commands::Admin.constants
|
28
|
+
.select { |c| Class === ClasslessMud::Commands::Admin.const_get(c) }
|
29
|
+
.map { |c| ClasslessMud::Commands::Admin.const_get(c) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ClasslessMud::Commands::Admin
|
2
|
+
class Kick
|
3
|
+
def self.perform game, player, message
|
4
|
+
other_player_name = message.split[1]
|
5
|
+
other_player = game.players.find { |player| player.name == other_player_name }
|
6
|
+
if other_player.nil?
|
7
|
+
player.puts "#{other_player_name} isn't here."
|
8
|
+
else
|
9
|
+
other_player.puts 'You are being kicked. Have a nice day!'
|
10
|
+
other_player.close_client
|
11
|
+
player.puts "You kicked #{other_player_name}."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class BadCommand
|
4
|
+
def self.perform game, player, message
|
5
|
+
if matches(message).any?
|
6
|
+
player.puts <<EOS
|
7
|
+
Did you mean:
|
8
|
+
#{matches(message).join(' ')}
|
9
|
+
EOS
|
10
|
+
else
|
11
|
+
player.puts 'You typed that wrong. Try again.'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.matches message
|
16
|
+
Suggestions.new(message.split(' ').first)
|
17
|
+
.matches(ClasslessMud::Commands::Commands.commands)
|
18
|
+
end
|
19
|
+
|
20
|
+
class Suggestions
|
21
|
+
attr_reader :word
|
22
|
+
|
23
|
+
def initialize(word)
|
24
|
+
@word = word
|
25
|
+
end
|
26
|
+
|
27
|
+
def length
|
28
|
+
word.length
|
29
|
+
end
|
30
|
+
|
31
|
+
def matches(potentials)
|
32
|
+
potentials & all
|
33
|
+
end
|
34
|
+
|
35
|
+
def all
|
36
|
+
deletions + transpositions + replacements
|
37
|
+
end
|
38
|
+
|
39
|
+
def deletions
|
40
|
+
(0..length).map { |i| "#{word[0...i]}#{word[i+1..-1]}" }
|
41
|
+
end
|
42
|
+
|
43
|
+
def transpositions
|
44
|
+
(0..length-1).map { |i| "#{word[0...i]}#{word[i+1, 1]}#{word[i,1]}#{word[i+2..-1]}" }
|
45
|
+
end
|
46
|
+
|
47
|
+
def replacements
|
48
|
+
(0..length-1).inject([]) do |sum, i|
|
49
|
+
sum += ('a'..'z').map { |c| "#{word[0...i]}#{c}#{word[i+1..-1]}" }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# Copyright notice
|
59
|
+
#
|
60
|
+
# Significant portions of this class were referenced from https://github.com/nithinbekal/spellingbee
|
61
|
+
#
|
62
|
+
# Copyright (c) 2010 Nithin Bekal
|
63
|
+
#
|
64
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
65
|
+
# a copy of this software and associated documentation files (the
|
66
|
+
# "Software"), to deal in the Software without restriction, including
|
67
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
68
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
69
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
70
|
+
# the following conditions:
|
71
|
+
#
|
72
|
+
# The above copyright notice and this permission notice shall be
|
73
|
+
# included in all copies or substantial portions of the Software.
|
74
|
+
#
|
75
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
76
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
77
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
78
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
79
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
80
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
81
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Chat
|
4
|
+
extend ::ClasslessMud::Colorizer
|
5
|
+
|
6
|
+
def self.perform game, player, message
|
7
|
+
command, message = message.split(' ', 2)
|
8
|
+
game.players.each do |player|
|
9
|
+
player.puts red("[CHAT] #{player.name}: #{message}")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative './bad_command'
|
2
|
+
|
3
|
+
module ClasslessMud
|
4
|
+
module Commands
|
5
|
+
# This is the commands command. The naming is weird, but this lists out all available commands
|
6
|
+
class Commands
|
7
|
+
COMMANDS_TO_HIDE = [BadCommand]
|
8
|
+
|
9
|
+
def self.commands
|
10
|
+
ClasslessMud::Commands.constants
|
11
|
+
.select { |c| Class === ClasslessMud::Commands.const_get(c) }
|
12
|
+
.reject { |c| COMMANDS_TO_HIDE.include?(ClasslessMud::Commands.const_get(c)) }
|
13
|
+
.map { |c| c.to_s.downcase }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.perform game, player, message
|
17
|
+
player.puts columnize(commands)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.columnize array, width=4
|
21
|
+
result = ''
|
22
|
+
longest_char = array.max_by(&:size).size
|
23
|
+
array.each_slice(width) do |row|
|
24
|
+
spaced_rows = row.map { |word| "%#{longest_char}s" % word }
|
25
|
+
result += spaced_rows.join(" ") + "\n"
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Dance
|
4
|
+
extend ClasslessMud::Colorizer
|
5
|
+
|
6
|
+
def self.perform game, player, message
|
7
|
+
player.puts red("Are you sure you want to dance? y/n: ")
|
8
|
+
player.on do |dance_response|
|
9
|
+
if dance_response == 'y' || dance_response == 'Y'
|
10
|
+
player.puts 'Well, what kind of dancing? '
|
11
|
+
player.on do |kind_response|
|
12
|
+
player.puts "You are #{kind_response} dancing"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Eat
|
4
|
+
def self.perform game, player, message
|
5
|
+
command, target = message.split " ", 2
|
6
|
+
found = item_from player, target
|
7
|
+
if found.nil?
|
8
|
+
player.puts "You do not have that"
|
9
|
+
else
|
10
|
+
if found.edible?
|
11
|
+
player.puts "You eat #{found.name}."
|
12
|
+
found.affect(player)
|
13
|
+
player.items.delete found
|
14
|
+
player.items.save!
|
15
|
+
else
|
16
|
+
player.puts "You cannot eat that!"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.item_from player, target
|
22
|
+
player.items.detect { |item| (item.keywords.split & target.split).any? }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Get
|
4
|
+
def self.perform game, player, message
|
5
|
+
get_command, get_target = message.split " ", 2
|
6
|
+
found = player.room.find get_target
|
7
|
+
if found
|
8
|
+
player.items << found
|
9
|
+
player.room.items.delete found
|
10
|
+
player.items.save!
|
11
|
+
player.room.items.save!
|
12
|
+
player.room.broadcast "#{player.name} picks up #{found.name}"
|
13
|
+
player.puts "You pick up #{found.name}"
|
14
|
+
else
|
15
|
+
player.puts "I don't see that anywhere"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Look
|
4
|
+
def self.perform game, player, message
|
5
|
+
look_command, look_target = message.split " ", 2
|
6
|
+
if !look_target
|
7
|
+
look_around player
|
8
|
+
else
|
9
|
+
look_at player, look_target
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.look_around player
|
14
|
+
player.puts player.room.description
|
15
|
+
|
16
|
+
if player.room.items.any?
|
17
|
+
items = player.room.items.map do |item|
|
18
|
+
item.short_description
|
19
|
+
end.join(", ")
|
20
|
+
|
21
|
+
player.puts "You also see: #{items}"
|
22
|
+
end
|
23
|
+
|
24
|
+
if player.room.characters.any?
|
25
|
+
characters = player.room.characters.map do |character|
|
26
|
+
character.name
|
27
|
+
end.join(", ")
|
28
|
+
|
29
|
+
player.puts "Here: #{characters}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.look_at player, look_target
|
34
|
+
found = player.room.find look_target
|
35
|
+
if found
|
36
|
+
player.puts found.short_description
|
37
|
+
else
|
38
|
+
player.puts "I don't see that anywhere"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Move
|
4
|
+
def self.perform game, player, message
|
5
|
+
direction = message.split[0]
|
6
|
+
valid_exit = player.room.exits.detect {|exit| exit.direction == direction}
|
7
|
+
if valid_exit
|
8
|
+
player.room.exit player
|
9
|
+
valid_exit.target.enter player
|
10
|
+
else
|
11
|
+
player.puts "You can't go that way."
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module ClasslessMud
|
2
|
+
module Commands
|
3
|
+
class Quit
|
4
|
+
def self.perform game, player, message
|
5
|
+
player.puts "Are you sure you want to quit? y/n: "
|
6
|
+
player.on do |response|
|
7
|
+
if response == 'y' || response == 'Y'
|
8
|
+
player.puts "Thanks for playing"
|
9
|
+
player.room.exit self
|
10
|
+
player.close_client
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|