Last active
April 16, 2016 02:41
-
-
Save rabbitt/9668062 to your computer and use it in GitHub Desktop.
interactive rubywarrior
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'readline' | |
require 'terminfo' | |
require 'abbrev' | |
require 'singleton' | |
$stty_save = %x{stty -g}.chomp | |
Signal.trap('WINCH', ->(*a) { Readline.set_screen_size(TermInfo.screen_size[0], TermInfo.screen_size[1]) }) | |
Signal.trap('INT', ->(*a) { system('stty', $stty_save); exit! }) | |
Signal.trap('QUIT', ->(*a) { system('stty', $stty_save); exit! }) | |
DIRECTIONS = %i( forward backward left right ) unless defined? DIRECTIONS | |
class RubyWarrior::Units::Warrior | |
# def shoot_power() 30; end | |
def character | |
case position.direction | |
when :north then '↑' | |
when :east then '→' | |
when :south then '↓' | |
when :west then '←' | |
end | |
end | |
unless instance_methods.include? :perform_turn_without_safety | |
alias_method :perform_turn_without_safety, :perform_turn | |
end | |
def perform_turn | |
perform_turn_without_safety | |
rescue RuntimeError => e | |
puts e.message | |
@current_turn.instance_variable_set(:@action, nil) | |
play_turn(@current_turn) | |
retry | |
end | |
unless instance_methods.include? :play_turn_without_safety | |
alias_method :play_turn_without_safety, :play_turn | |
end | |
def play_turn(turn) | |
play_turn_without_safety(turn) | |
rescue RuntimeError => e | |
puts e.message | |
@current_turn.instance_variable_set(:@action, nil) | |
play_turn(@current_turn) | |
end | |
end | |
class Player | |
class Readline | |
include Singleton | |
class << self | |
def method_missing(method, *args, &block) | |
return super unless instance.public_methods.include? method | |
instance.public_send(method, *args, &block) | |
end | |
end | |
attr_accessor :prompt, :choices | |
def initialize | |
@prompt = '?' | |
@choices = [] | |
end | |
def readline | |
::Readline.completion_append_character = " " | |
::Readline.completion_proc = ->(s) { choices.grep(/^#{Regexp.escape(s)}/) } | |
::Readline.readline(prompt, true).tap do |response| | |
return '' if response.nil? | |
::Readline::HISTORY.pop if response !~ /\S/ || ::Readline::HISTORY.to_a[-2] == response | |
end | |
end | |
end | |
def initialize | |
@warrior = nil | |
@abilities = [] | |
Readline.prompt = 'Enter Command (? for commands, [tab] to complete): ' | |
end | |
def commands | |
(@abilities | DIRECTIONS | %w(exit console quit ?)).tap { |coms| | |
coms << :heal if @warrior.respond_to? :rest! | |
coms << :feel if @warrior.respond_to? :feel | |
coms << :look if @warrior.respond_to? :look | |
coms << :stairs if @warrior.respond_to? :direction_of_stairs | |
} | |
end | |
def command_lookup(command) | |
abbreviated_command_lookup = Hash[ | |
commands.collect(&:to_s).abbrev.collect { |key,value| [key.to_sym, value.to_sym] } | |
][command] || command | |
end | |
def play_turn(warrior) | |
@abilities = warrior.methods(false).grep(/\!/).sort.reject { |m| m == :action } | |
Readline.choices = commands.collect(&:to_s) | |
# once we have the ability to feel, we can grab the warrior object | |
if warrior.respond_to? :feel | |
space = warrior.feel :forward | |
@warrior = space.instance_variable_get(:@floor).unique_units.find { |u| | |
u.is_a? RubyWarrior::Units::Warrior | |
} | |
end | |
begin | |
response = get_user_input(commands) | |
response.collect! { |word| command_lookup(word) } | |
case response.first.to_s | |
when 'quit', 'exit' then | |
exit! | |
when '?' then | |
puts "Available Actions: #{commands.collect(&:to_s).join(', ')}" | |
redo | |
when 'feel', 'look', 'feel_around' then | |
if warrior.respond_to? response.first | |
objects = examine_spaces(warrior.send(*response.collect(&:to_sym))) | |
direction = case response[1] | |
when :forward, nil then 'ahead of' | |
when :backward then 'behind' | |
end | |
puts "You see #{direction} you:\n #{objects.join("\n ")}" | |
else | |
puts "Unable to #{response.first} right now." | |
end | |
redo | |
when 'console' then | |
begin | |
require 'pry' | |
binding.pry | |
rescue LoadError | |
puts "Pry library not installed. Install using: gem install pry" | |
redo | |
end | |
redo | |
when 'heal' then | |
response = [:rest!] | |
break | |
when 'stairs' then | |
response = [:walk!, warrior.direction_of_stairs] | |
break | |
when /(#{DIRECTIONS.join('|')})/i then | |
response = [:walk!, response.first] | |
break | |
when *@abilities.collect(&:to_s) then | |
break | |
else | |
puts "Unknown or ambiguous command: '#{response.first}'" | |
next | |
end | |
end until commands.include?(response.first) | |
warrior.send(*response.collect(&:to_sym)) | |
end | |
private | |
def examine_spaces(spaces) | |
spaces.collect { |space| describe_space(space) } | |
end | |
def describe_space(space) | |
description = if space.unit | |
case true | |
when space.golem? then 'A Golem' | |
when space.player? then 'You' | |
when space.enemy? then | |
if space.unit.name[0] =~ /[aeiou]/i | |
"An #{space.unit.name} (#{space.unit.health} / #{space.unit.max_health})" | |
else | |
"A #{space.unit.name} (#{space.unit.health} / #{space.unit.max_health})" | |
end | |
when space.captive? then 'A captive' | |
when space.ticking? then 'A bomb!' | |
else 'An unknown Unit' | |
end | |
else | |
case true | |
when space.wall? then 'A wall' | |
when space.stairs? then 'Stairs' | |
when space.empty? then 'Empty floor' | |
else 'A mysterious space' | |
end | |
end | |
end | |
def score | |
@warrior ? @warrior.score : 0 | |
end | |
def score_text | |
"Score: #{score}" | |
end | |
def health_text | |
return "Health [ ? / ? ]" unless @warrior | |
"Health: [%s / %s]" % [ @warrior.health, @warrior.max_health] | |
end | |
def weapon_text | |
weapons = [] | |
if @abilities.include? :attack! | |
power = @warrior ? @warrior.attack_power : '?' | |
weapons << "sword(#{power})" | |
end | |
if @abilities.include? :shoot! | |
power = @warrior ? @warrior.shoot_power : '?' | |
weapons << "bow(#{power})" | |
end | |
weapons = %w'none' if weapons.empty? | |
"Weapons: #{weapons.join(' / ')}" | |
end | |
def readline | |
Readline.readline | |
end | |
def get_user_input(commands) | |
puts "\n#{health_text} | #{weapon_text} | #{score_text}" | |
response = readline.to_s.downcase.strip.split(/\s+/).collect(&:to_sym) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment