home *** CD-ROM | disk | FTP | other *** search
/ Solo Programadores 22 / SOLO_22.iso / docs / lovelace / things.adb < prev    next >
Encoding:
Text File  |  1995-11-21  |  6.7 KB  |  231 lines

  1.  
  2. with Text_IO, Ustrings;
  3. use  Text_IO, Ustrings;
  4.  
  5.  
  6. package body Things is
  7.  
  8.  -- Define basic types for the world and their operations.
  9.  
  10.  
  11.  -- Supporting Subprograms:
  12.  
  13.  procedure Sorry(Prohibited_Operation : String;
  14.                  Prohibited_Direct_Object : Unbounded_String) is
  15.  begin
  16.   Put_Line("Sorry, you may not " & Prohibited_Operation & " the " &
  17.            S(Prohibited_Direct_Object));
  18.  end Sorry;
  19.  
  20.  
  21.  -- Routines to manipulate First_Containee, Next_Sibling, Container:
  22.  
  23.  function Previous_Sibling(Containee : access Thing'Class)
  24.           return Thing_Access is
  25.   -- Find the previous sibling of containee.  It's an error to call
  26.   -- this if Containee has no previous sibling.
  27.     Current : Thing_Access := Containee.Container.First_Containee;
  28.  begin
  29.     while Current.Next_Sibling /= Thing_Access(Containee) loop
  30.       Current := Current.Next_Sibling;
  31.     end loop;
  32.     return Current;
  33.  end Previous_Sibling;
  34.  
  35.  function Last_Containee(Container : access Thing'Class)
  36.           return Thing_Access is
  37.    -- Return an access value of the last contained Thing in container.
  38.    -- It's an error to call this routine if there are no containees.
  39.     Current : Thing_Access := Container.First_Containee;
  40.  begin
  41.     while Current.Next_Sibling /= null loop
  42.       Current := Current.Next_Sibling;
  43.     end loop;
  44.     return Current;
  45.  end Last_Containee;
  46.  
  47.  procedure Remove(Containee : access Thing'Class) is
  48.  -- Remove Containee from its current Container.
  49.   Previous_Thing : Thing_Access;
  50.  begin
  51.   if Containee.Container /= null then
  52.     if Containee.Container.First_Containee = Thing_Access(Containee) then
  53.        -- Containee is the first Thing in its container.
  54.        Containee.Container.First_Containee := Containee.Next_Sibling;
  55.     else
  56.        Previous_Thing := Previous_Sibling(Containee);
  57.        Previous_Thing.Next_Sibling := Containee.Next_Sibling;
  58.     end if;
  59.     Containee.Next_Sibling := null;
  60.     Containee.Container    := null;
  61.   end if;
  62.  end Remove;
  63.  
  64.  
  65.  procedure Place(T : access Thing'Class; Into : Thing_Access) is
  66.  -- Place "T" inside "Into".
  67.   Last : Thing_Access;
  68.  begin
  69.   if (Thing_Access(T) = Into) then
  70.     Put_Line("Sorry, that can't be done.");
  71.     return;
  72.   end if;
  73.   Remove(T); -- Remove Thing from where it is now.
  74.   if Into /= null then
  75.     if Into.First_Containee = null then
  76.       Into.First_Containee := Thing_Access(T);
  77.     else
  78.       Last := Last_Containee(Into);
  79.       Last.all.Next_Sibling := Thing_Access(T);
  80.     end if;
  81.   end if;
  82.   T.Container := Into;
  83.  end Place;
  84.  
  85.  procedure Put_Contents(T : access Thing'Class;
  86.                         Ignore : access Thing'Class;
  87.                         Heading_With_Contents : in String;
  88.                         Heading_Without_Contents : in String := "") is
  89.    -- Put a description of the contents of T.
  90.    -- If there is something, print Heading_With_Contents;
  91.    -- If there isn't something, print Heading_Without_Contents.
  92.    -- Ignore The_Player, since presumably the player already knows about
  93.    -- him/herself.
  94.    Current : Thing_Access := T.First_Containee;
  95.    Have_Put_Something : Boolean := False;
  96.  begin
  97.   while Current /= null loop
  98.     if Current /= Thing_Access(Ignore) then
  99.       -- This what we're to ignore, print it out.
  100.       if Have_Put_Something then
  101.         Put(", ");
  102.       else
  103.         -- We're about to print the first item; print the heading.
  104.         Put_Line(Heading_With_Contents);
  105.       end if;
  106.       Put(Short_Description(Current));
  107.       Have_Put_Something := True;
  108.     end if;
  109.     Current := Current.Next_Sibling;
  110.   end loop;
  111.   if Have_Put_Something then
  112.     Put_Line(".");
  113.   elsif Heading_With_Contents'Length > 0 then
  114.     Put_Line(Heading_Without_Contents);
  115.   end if;
  116.  end Put_Contents;
  117.  
  118.  
  119.  -- Dispatching Operations:
  120.  
  121.  function What_Is(From : access Thing; Dir : in Direction)
  122.           return Thing_Access is
  123.  begin
  124.    return null; -- As a default, you can't go ANY direction from "here".
  125.  end What_Is;
  126.  
  127.  
  128.  -- Non-dispatching public operations:
  129.  
  130.  procedure Set_Name(T : access Thing'Class; Article : in Article_Type;
  131.                     Name : in Unbounded_String) is
  132.  begin
  133.    T.Article := Article;
  134.    T.Name    := Name;
  135.  end Set_Name;
  136.  
  137.  procedure Set_Name(T : access Thing'Class; Article : in Article_Type;
  138.                     Name : in String) is
  139.  begin
  140.    T.Article := Article;
  141.    T.Name    := To_Unbounded_String(Name);
  142.  end Set_Name;
  143.  
  144.  function Name(T : access Thing'Class) return Unbounded_String is
  145.  begin
  146.   return T.Name;
  147.  end Name;
  148.  
  149.  procedure Set_Description(T : access Thing'Class;
  150.                            Description : in Unbounded_String) is
  151.  begin
  152.   T.Description := Description;
  153.  end Set_Description;
  154.  
  155.  procedure Set_Description(T : access Thing'Class;
  156.                            Description : in String) is
  157.  begin
  158.   T.Description := To_Unbounded_String(Description);
  159.  end Set_Description;
  160.  
  161.  function Long_Description(T : access Thing'Class) return Unbounded_String is
  162.  begin
  163.    return T.Description;
  164.  end Long_Description;
  165.  
  166.  
  167.  -- Eventually we'll use an array for the article, but a minor GNAT 2.7.0 bug
  168.  -- will cause this to raise a Segmentation Fault when the program quits:
  169.  -- Article_Text : constant array(Article_Type) of Unbounded_String :=
  170.  --     (A => U("a "), An => U("an "), The => U("the "), Some => U("some "),
  171.  --      None => U(""));
  172.  
  173.  function Short_Description(T : access Thing'Class) return Unbounded_String is
  174.  begin
  175.   case T.Article is
  176.    when A    => return "a "    & T.Name;
  177.    when An   => return "an "   & T.Name;
  178.    when The  => return "the "  & T.Name;
  179.    when Some => return "some " & T.Name;
  180.    when None => return           T.Name;
  181.   end case;
  182.   -- Should become return Article_Text(T.Article) & T.Name;
  183.  end Short_Description;
  184.  
  185.  function Find(Agent : access Thing'Class;
  186.                Object_Name : in Unbounded_String) return Thing_Access is
  187.  begin
  188.    if Agent.Container = null then
  189.      Put_Line("You aren't in anything.");
  190.      return null;
  191.    else
  192.      return Find_Inside(Agent.Container, Object_Name);
  193.    end if;
  194.  end Find;
  195.  
  196.  function Find_Inside(Agent : access Thing'Class;
  197.                       Object_Name : in Unbounded_String)
  198.           return Thing_Access is
  199.    Current : Thing_Access := Agent.First_Containee;
  200.  begin
  201.    if Empty(Object_Name) then
  202.      Put_Line("Sorry, you need to name an object.");
  203.      return null;
  204.    end if;
  205.    while Current /= null loop
  206.      if Current.Name = Object_Name then
  207.        return Current;
  208.      end if;
  209.      Current := Current.Next_Sibling;
  210.    end loop;
  211.    Put("Sorry, I don't see a ");
  212.    Put_Line(Object_Name);
  213.    return null;
  214.  end Find_Inside;
  215.  
  216.  function Container(T : access Thing'Class) return Thing_Access is
  217.  begin
  218.    return T.Container;
  219.  end Container;
  220.  
  221.  function Has_Contents(T : access Thing'Class) return Boolean is
  222.  begin
  223.    if T.First_Containee = null then
  224.      return False;
  225.    else
  226.      return True;
  227.    end if;
  228.  end Has_Contents;
  229.  
  230. end Things;
  231.