classless_mud 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|