classless_mud 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/Gemfile +4 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +32 -0
  6. data/Rakefile +5 -0
  7. data/bin/classless_mud +11 -0
  8. data/classless_mud.gemspec +29 -0
  9. data/conf/settings.yml +4 -0
  10. data/lib/classless_mud.rb +72 -0
  11. data/lib/classless_mud/account_builder.rb +81 -0
  12. data/lib/classless_mud/character.rb +39 -0
  13. data/lib/classless_mud/character_sheet.rb +26 -0
  14. data/lib/classless_mud/character_sheet_builder.rb +72 -0
  15. data/lib/classless_mud/client.rb +47 -0
  16. data/lib/classless_mud/colorizer.rb +33 -0
  17. data/lib/classless_mud/commands.rb +32 -0
  18. data/lib/classless_mud/commands/admin/kick.rb +15 -0
  19. data/lib/classless_mud/commands/bad_command.rb +81 -0
  20. data/lib/classless_mud/commands/character.rb +9 -0
  21. data/lib/classless_mud/commands/chat.rb +14 -0
  22. data/lib/classless_mud/commands/commands.rb +31 -0
  23. data/lib/classless_mud/commands/dance.rb +20 -0
  24. data/lib/classless_mud/commands/eat.rb +26 -0
  25. data/lib/classless_mud/commands/get.rb +20 -0
  26. data/lib/classless_mud/commands/inventory.rb +12 -0
  27. data/lib/classless_mud/commands/look.rb +43 -0
  28. data/lib/classless_mud/commands/move.rb +16 -0
  29. data/lib/classless_mud/commands/quit.rb +16 -0
  30. data/lib/classless_mud/commands/say.rb +10 -0
  31. data/lib/classless_mud/commands/score.rb +12 -0
  32. data/lib/classless_mud/commands/whisper.rb +17 -0
  33. data/lib/classless_mud/commands/who.rb +9 -0
  34. data/lib/classless_mud/effect.rb +14 -0
  35. data/lib/classless_mud/exit.rb +15 -0
  36. data/lib/classless_mud/game.rb +40 -0
  37. data/lib/classless_mud/game_master.rb +12 -0
  38. data/lib/classless_mud/input_parser.rb +7 -0
  39. data/lib/classless_mud/item.rb +21 -0
  40. data/lib/classless_mud/npc.rb +12 -0
  41. data/lib/classless_mud/player.rb +57 -0
  42. data/lib/classless_mud/room.rb +60 -0
  43. data/lib/classless_mud/server.rb +18 -0
  44. data/lib/classless_mud/version.rb +3 -0
  45. data/lib/classless_mud/world.rb +26 -0
  46. data/tasks/db.rake +10 -0
  47. 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,9 @@
1
+ module ClasslessMud
2
+ module Commands
3
+ class Character
4
+ def self.perform game, player, message
5
+ player.character_sheet.display
6
+ end
7
+ end
8
+ end
9
+ end
@@ -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,12 @@
1
+ module ClasslessMud
2
+ module Commands
3
+ class Inventory
4
+ def self.perform game, player, message
5
+ player.puts "Inventory:"
6
+ player.items.each do |item|
7
+ player.puts " #{item.name}"
8
+ end
9
+ end
10
+ end
11
+ end
12
+ 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
@@ -0,0 +1,10 @@
1
+ module ClasslessMud
2
+ module Commands
3
+ class Say
4
+ def self.perform game, player, message
5
+ say_command, say_message = message.split(' ', 2)
6
+ player.room.broadcast_say player, say_message
7
+ end
8
+ end
9
+ end
10
+ end