CoralMUD-0.15/
CoralMUD-0.15/core/
CoralMUD-0.15/data/
CoralMUD-0.15/data/areas/
CoralMUD-0.15/data/help/
CoralMUD-0.15/data/players/
CoralMUD-0.15/lib/automap/
CoralMUD-0.15/lib/items/
require 'core/creation_data'

module SocketData
  ### Attaches a nanny to a socket.  It only exists while in creation.
  def assign_nanny
    @nanny = Fiber.new do
      ### enter login menu
      text_to_socket $greeting
      text_to_socket "#nWhat is your name? "

      ### yield and on next call set arg
      while !check_name((narg = Fiber.yield false).capitalize)
        text_to_socket "That's not a valid name.  What is your name?" + ENDL
        log :info, "-- #{@addr}:#{@port}: (#{narg}) Invalid name in character creation."
      end

      ### ensures the name is capital.
      narg.capitalize!
      log :info, "-- #{@addr}:#{@port}: #{narg} is trying to connect."
      ### valid name found. We should create their player now.
      text_to_socket "Thank you." + ENDL


      if File.exists?("data/players/#{narg.downcase.capitalize}.yml") == false
      ### If a new player is not found we need to create a new one.
        log :info, "-- #{@addr}:#{@port}: #{narg}:  New Character."
        @player = Player.new

        @player.name = narg.dup
        # prepare for next step

        text_to_socket DONT_ECHO
        ### This will loop until both passwords match.
        loop do
          text_to_socket "Please enter a new password: "
          while !check_pass((parg = Fiber.yield false))
            ### We could also explain here what constitutes a valid password.
            text_to_socket "That's not a valid password.  What is your new password#{ENDL}: "
          end

          ### Ask them to reenter their password.
          text_to_socket "Thank you.  Can you please verify the password?" + ENDL

          p2arg = Fiber.yield false

          if parg.eql? p2arg
            text_to_socket "Passwords match." + ENDL
            @player.password = parg.dup
            break
          else
            text_to_socket "Passwords do not match." + ENDL
          end
        end
        text_to_socket DO_ECHO

        text_to_socket "Entering character creation." + ENDL
        text_to_socket "Enter any key to continue . . ." + ENDL
        Fiber.yield false

        creation_menu = enter_creation_menu()
        creation_menu.resume "" # Start menu system.
        ### enter creation menu.
        loop do
          # Break after the creation menu is no longer active.
          if !creation_menu.alive?
            break
          end
          if creation_menu.resume(Fiber.yield false)
            break
          end
        end
        ### End character creation loop
        ###
        ###
        log :info, "-- #{@addr}:#{@port}: #{@player.name} successfully created."
      else
        log :info, "-- #{@addr}:#{@port}: #{narg} player file found." 
        @player = Player.load_pfile(narg)
        ### old player found.
        ### do this until passwords match.
        attempt = 0
        text_to_socket DONT_ECHO
        begin
          log :info, "-- #{@addr}:#{@port}: #{@player.name} password incorrect." if attempt > 0
          attempt += 1
          if attempt > 3
            log :info, "-- #{@ip}: #{@port} has been disconnected for 3 failed attempts for #{@player.name}."
            Fiber.yield true
          end
          text_to_socket "Password: "
          parg = Fiber.yield false
        end while parg != @player.password
        text_to_socket DO_ECHO
        text_to_socket "Password matches.  Thank you." +ENDL

        if (@player = check_reconnect(@player.name)) != nil
          @state = :state_playing
          log :info, "-- #{@addr}:#{@port}: #{@player} has reconnected."
          text_to_socket "You take over a body already in use." + ENDL
        elsif (@player = Player.load_pfile(narg)) == nil
          text_to_socket "ERROR: Your pfile is missing!" + ENDL
          log :info, "-- #{narg}'s pfile was missing after originally found."
          Fiber.yield true
        end
      end

      @state = :state_playing
      log :info, "-- #{@player.name} has entered the game."
      @player.to_room(ROOM_ON_CREATE)
      text_to_socket $motd
      @player.socket = self
      $dplayer_list << @player if !$dplayer_list.include? @player
      @player.execute_command("look");
      @player.save_pfile
      false
    end

    @nanny.resume ""
  end
















  def enter_creation_menu 
    return Fiber.new do 
      ### dump the menu options 
      ### generate the menu each pass.
      length = 79
      ### CREATION TABLE
      ### To add more creation categories add to this table.
      ccmenu =[
             {:tag=>'1', :desc=>"race",          :data=>CCDEFAULT_DATA, :count=>1, :table=>$ccmenu_element[:menu_race],:question=>"Please choose a race."},
             {:tag=>'2', :desc=>"class",         :data=>CCDEFAULT_DATA, :count=>1, :table=>$ccmenu_element[:menu_class],:question=>"Please choose a class."},
             {:tag=>'3', :desc=>"sign",          :data=>CCDEFAULT_DATA, :count=>1, :table=>$ccmenu_element[:menu_signs],:question=>"Under which sign were you born?"},
             {:tag=>'4', :desc=>"traits",        :data=>CCDEFAULT_DATA, :count=>3, :table=>$ccmenu_element[:menu_traits],:question=>"Please pick 3 traits."},
             {:data=>"".ljust(length-2, "-")},                      ### This line has no way of accessing it but the data still will be printed.
             {:tag=>'q', :desc=>"quit"}]
      ### At this point we should enter our menu driven system. 

      loop do
        buf =  "#w" + "#W________________________".ljust(length, '_') + ENDL
        buf << "#w" + "#W___#BCHARACTER CREATION#W___".ljust(length, '_') + ENDL
        ccmenu.each do |main_menu_option|
          t = ""
          ### Each m is a map
          t << "%3s)" % main_menu_option[:tag] + " " if main_menu_option[:tag] != nil
          t << main_menu_option[:desc].o_ljust(18) + " " if main_menu_option[:desc] != nil

          ### Depending on the type of data we may do something different with it.
          ### Type String:  Print it
          ### Type Array: Print on each line.
          if main_menu_option[:data] == nil
            buf << "#W=" + t.o_ljust(length-2) + "#W=" + ENDL
          elsif main_menu_option[:data].is_a? String
            tmp = main_menu_option[:data]
            if tmp.eql? CCDEFAULT_DATA
              t.insert(0, "#R")
            else
              t.insert(0, "#W")
            end
            t << tmp
            buf << "#W=" + t.ljust(length-2) + "#W=" + ENDL
          elsif main_menu_option[:data].is_a? Array
            datum = main_menu_option[:data]
            if datum.length == 1
              t << main_menu_option[:table][datum[0]][:name]
              buf << "#W=" + t.ljust(length-2) + "#W=" + ENDL
              next
            end
            t.gsub!(" ", "_")
            buf << "#W=" + "#W" + t.o_ljust(length-2, '_') + "#W=" + ENDL
            datum.each do |e|
              ### For each element in the array dump an explaination on its own line.
              tmp = main_menu_option[:table][e][:desc].dup
              tmp_n = main_menu_option[:table][e][:name]
              ccc = 0
              while !tmp.empty?
                if ccc == 0
                  buf << "#W= " + " #C#{'%-20s' % tmp_n}#C " + tmp.pop_some(length-4-22).ljust(length-4-22) + "#W =" + ENDL
                else
                  buf << "#W= " + "#C" + tmp.pop_some(length-4).ljust(length-4) + "#W =" + ENDL
                end
                ccc += 1
              end
            end
          end
        end
        buf << "#W"+ "==[#{Time.now.strftime("#R%I:%M%p#w")}#W]==".rjust(length, '=') + ENDL
        text_to_socket buf
        text_to_socket "Please make a selection:"

        # receive input for menu.
        argselect = Fiber.yield false

        ### parse the options and see if any match
        menufound = nil
        ccmenu.each do |v|
          next if v[:tag] == nil

          if argselect.eql? v[:tag].downcase
            ### And this is ugly because each field has a totally different check against the parameter.
            ### We're trying to streamline it based on how many options and the table of options.
            menufound = v
          end
        end
        if menufound == nil ### This means the user option was not found on the menu.
          text_to_socket "That is not a valid option." + ENDL
        else
          ### We found The key
          if menufound[:tag].eql? "q"
            ### This is the quit option.  Special case for this since it is for breaking the loop.
            ### Check to see if every condition is met.
            all_cond_met = true
            ccmenu.each do |check_each|
              next if check_each[:tag] == nil || check_each[:data] == nil

              if !check_each[:data].is_a?(Array)
                all_cond_met = false
                break
              end
              if check_each[:data].length != check_each[:count]
                all_cond_met = false
                break
              end
            end
            if !all_cond_met
              text_to_socket "All conditions are not met." + ENDL
              text_to_socket "Enter any key to continue . . ." + ENDL
              Fiber.yield false
            else
              text_to_socket "Thank you.  All conditions are met." + ENDL
              text_to_socket "Enter any key to continue . . ." + ENDL
              Fiber.yield false
              ### convert the data we mined into data on the Player structure.
              ccmenu.each do |elem|
                case elem[:desc]
                  when "race" then    @player.race = elem[:data][0]
                  when "class" then   @player.clas = elem[:data][0]
                  when "traits" then  @player.traits = elem[:data].dup
                  when "sign" then    @player.sign =  elem[:data][0]
                end
              end
              break
            end
          else ### Otherwise figure out which table we're using and let them select a certain number of options.
            ### First clear the data
            menufound[:data] = []
            print_menu_options(self, menufound)
            loop do ### print the current menu and its selections.  
              if menufound[:data].length != 0
                text_to_socket "#W".center(length, '_') + ENDL
                text_to_socket "#W__#BYOUR #{menufound[:desc].upcase}#W".ljust(length, '_') + ENDL
                text_to_socket "= Empty".ljust(length-2) + " =" + ENDL if menufound.empty?
                menufound[:data].each do |mmm|
                  text_to_socket "= " + menufound[:table][mmm][:name].ljust(length-4) + " =" + ENDL
                end
                text_to_socket "#W= " + "".center(length-4, '=') + " =#n" + ENDL
              end
              break if menufound[:data].count >= menufound[:count]
              text_to_socket menufound[:question] + ENDL
              text_to_socket ">>>"
              argselect = Fiber.yield false ### Accept input

              ### Match argselect against menufound[:table] values
              mfound = false
              menufound[:table].each do |k, v|
                if argselect.eql?(v[:name].downcase) && !menufound[:data].include?(k)
                  ### we found a valid object. We should add the key to the data.
                  menufound[:data] << k
                  mfound = true
                  break
                end
              end
              next if mfound == true
              text_to_socket "That is not a valid selection." + ENDL
              text_to_socket "Enter any key to continue . . ." + ENDL
              Fiber.yield false
              print_menu_options(self, menufound)
            end
          end
        end
      end ### MENU LOOP
    end ### Entire thing in a fiber returned.
  end
end