Pocket code and inv_desc

This is a discussion / support forum for the Hugo programming language by Kent Tessman. Hugo is a powerful programming language for making text games / interactive fiction with multimedia support.

Hugo download links: https://www.generalcoffee.com/hugo
Roody Yogurt's Hugo Blog: https://notdeadhugo.blogspot.com
The Hugor interpreter by RealNC: http://ifwiki.org/index.php/Hugor

Moderators: Ice Cream Jonsey, joltcountry

Bainespal
Posts: 151
Joined: Fri Jul 09, 2010 8:59 am

Pocket code and inv_desc

Post by Bainespal »

In the first Hugo game that I made and never released or debugged a few years ago, I had a coat with a component object representing the coat pockets. The code worked for taking things out of the pockets and putting them back in again, but the inventory listing was a problem.

Today I revisited the code. I got rid of the component object, merging everything into the coat. It's still not perfect, because I can't get both the coat objects inv_desc and contains_desc properties to be displayed on inventory. Inv_desc seems to override contains_desc. I can still see the contains_desc when I explicitly type "LOOK IN COAT," but I want it to appear for the inventory list as well.

I was thinking this might be a good one for the "Quick Code Samples" thread, but it's still not quite right, so I'll post code here anyways:

Code: Select all

object coat "coat"
{
  is clothing, worn, container
  in you
    nouns "coat", "jacket", "windbreaker", "pockets", "pocket"
    adjective "synthetic"
    article "your"
    long_desc
    {
      "An inexpensive synthetic windbreaker with two large pockets."
    }
    inv_desc
    {
      "You are ";
      if self is worn
      {
        print "wearing ";
      }
      else
      {
        print "carrying ";
      }
      print Art(self); ".";
    }
    contains_desc
    {
      "Inside the coat's pockets ";
      if Children(self) > 1
      {
        print "are";
      }
      else
      {
        print "is";
      }
    }
    capacity 10
}
And here's the portable object that begins in the coat pocket:

Code: Select all

object keychain "keychain"
{
  in coat
    nouns "keychain", "chain", "keyring", "ring", "fob", "keys", "attachments"
    adjectives "plastic", "key", "miscellaneous"
    article "your"
}

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

Interesting problem. I will look into this.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

Ok, to get this working how I'd like, it took some finessing of WhatsIn and SpecialDesc. Working with important but complicated routines like WhatsIn and Parse always make me feel like trying to fix a leaky boat, but I'm sure whatever new leaks I spring will bring us closer to better routines in the long run.

Here are the updated routines:

Code: Select all

!\ Added some code so that if the obj is the only child of a parent, it still
checks (and lists) any children of that obj. \!

replace SpecialDesc(obj)
{
	local a, c, flag, printed_blankline

	if FORMAT & LIST_F
		return

	list_count = 0
	for a in obj
	{
		if a is not hidden
		{
			c++
			flag = true
		}
		else
			flag = false

		if FORMAT & INVENTORY_F and obj = player and flag
		{
			if &a.inv_desc
				Indent
			if a.inv_desc
			{
				if FORMAT & LIST_F:  print newline
				AddSpecialDesc(a)
			}
		}

		elseif a is not moved and flag
		{
			if &a.initial_desc
			{
				print newline
				override_indent = false
				if FORMAT & INVENTORY_F and FORMAT & NOINDENT_F and not printed_blankline
					print ""
				printed_blankline = true
				Indent
			}
			if a.initial_desc
				AddSpecialDesc(a)
		}
	}
	list_count = c - list_count
	if not list_count and c
	{
		for a in obj
		{
			if children(a) and a is not quiet and (a is platform or a is transparent or (a is container and a is open)) and
			not a.list_contents
			{
				WhatsIn(a)
				list_count = 0
			}
		}
	}
}

! changed a carriage return to 'print newline'
replace WhatsIn(obj)
{
	local i, totallisted
	local initial_list_nest

	if FORMAT & NORECURSE_F
		return

	for i in obj
	{
		i is not already_listed
		if i is not hidden
			totallisted++
	}

	if totallisted = 0
		return

	list_count = totallisted

	if obj is not container or (obj is container and obj is platform) or
		(obj is container and (obj is not openable or
			(obj is openable and
				(obj is open or obj is transparent)))) and
		(obj ~= player or FORMAT & INVENTORY_F) and obj is not quiet
	{
		SpecialDesc(obj)

		! If list_count is 0 now, but totallisted was not, something must have been
		! printed by SpecialDesc


		if list_count = 0
		{
			if FORMAT & INVENTORY_F and not (FORMAT & LIST_F) and
				list_nest = 0
			{
!				print ""
				print newline
			}
			return totallisted
		}

			if obj.list_contents
			return totallisted

		initial_list_nest = list_nest

		if FORMAT & LIST_F
		{
			if list_nest
			{
				! Indent the first time so that it lines up with
				! paragraph indentation:
				i = list_nest
				if list_nest = 1 and not (FORMAT & NOINDENT_F)
				{
					Indent
					i--
				}

				print to (i * 2);	! INDENT_SIZE);
			}
		}
		else
		{
			Indent
		}

		if obj.contains_desc    ! custom heading
		{
			if FORMAT & LIST_F
				RLibMessage(&WhatsIn, 1 )  !  ":"
		}
		else
		{
			if obj = player
			{
				if FORMAT & LIST_F and list_count < totallisted
					print "\n";

				! "You are carrying..."
				Message&#40;&WhatsIn, 1, totallisted&#41;

				if FORMAT & LIST_F
					RLibMessage&#40;&WhatsIn, 1 &#41;  !  "&#58;"
			&#125;
			elseif obj is living and not obj.prep
			&#123;
				! "X has..."
				Message&#40;&WhatsIn, 2, obj, totallisted&#41;
				if FORMAT & LIST_F
					RLibMessage&#40;&WhatsIn, 1 &#41;  !  "&#58;"
			&#125;
			else
			&#123;
				if list_count < totallisted
					! "Also sitting on/in..."
					Message&#40;&Whatsin, 3, obj&#41;
				else
					! "Sitting on/in..."
					Message&#40;&Whatsin, 4, obj&#41;
				The&#40;obj&#41;
				FORMAT = FORMAT | ISORARE_F
			&#125;
		&#125;

		ListObjects&#40;obj&#41;

		list_nest = initial_list_nest
	&#125;
	return totallisted
&#125;
This gives us a couple options. If we code the coat like this:

Code: Select all

object coat "coat"
&#123;
  is clothing, worn, container, open
  in you
    nouns "coat", "jacket", "windbreaker", "pockets", "pocket"
    adjective "synthetic"
    article "your"
    long_desc
    &#123;
      "An inexpensive synthetic windbreaker with two large pockets."
    &#125;
    inv_desc
    &#123;
      if self is worn
      &#123;
        print "You are wearing ";
      &#125;
      else  ! if it isn't worn, we can treat it like a regular object
      &#123;
        return false
      &#125;
      print Art&#40;self&#41;; "."
    &#125;
    contains_desc
    &#123;
      "Inside the coat's pockets ";
      if Children&#40;self&#41; > 1
      &#123;
        print "are";
      &#125;
      else
      &#123;
        print "is";
      &#125;
    &#125;
    capacity 10
&#125;
It'll default to responses like this, where the coat's children may be listed after everything else the player is carrying:
> i
You are wearing your coat.
You are also carrying some toast. Inside the coat’s pockets is your keychain.

>
That may not be ideal, but it's workable. Still, we can use list_contents to determine when and how we want the coat's children to be listed. It's nice and powerful that way:

Code: Select all

object coat "coat"
&#123;
  is clothing, worn, container, open
  in you
    nouns "coat", "jacket", "windbreaker", "pockets", "pocket"
    adjective "synthetic"
    article "your"
    long_desc
    &#123;
      "An inexpensive synthetic windbreaker with two large pockets."
    &#125;
    inv_desc
    &#123;
      if self is worn
      &#123;
        print "You are wearing ";
      &#125;
      else  ! if it isn't worn, we can treat it like a regular object
      &#123;
        return false
      &#125;
      print Art&#40;self&#41;; ".";
		if children&#40;self&#41;
		&#123;
			print AFTER_PERIOD;
			run self.contains_desc
			ListObjects&#40;self&#41;
		&#125;
		else
			""
    &#125;
	 list_contents
	 &#123;
		if &#40;verbroutine = &DoLookIn,&DoLook&#41; or self is not worn and
		verbroutine ~= &DoLookAround
		&#123;
			return false
		&#125;
		return true
	 &#125;
    contains_desc
    &#123;
      "Inside the coat's pockets ";
      if Children&#40;self&#41; > 1
      &#123;
        print "are";
      &#125;
      else
      &#123;
        print "is";
      &#125;
    &#125;
    capacity 10
&#125;
This results in:
> i
You are wearing your coat. Inside the coat’s pockets is your keychain.
You are also carrying some toast.

>
Let me know if you have any other thoughts on this.

EDIT: Added the list_contents code above to also allow &DoLook
Last edited by Roody_Yogurt on Fri Jun 28, 2013 11:40 am, edited 1 time in total.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

One other thing! It bugged me that with the above, we got a default message ("The coat is empty.") when it has no children. To fix this, we add the following to the coat object:

Code: Select all

	 after
	 &#123;
			object DoLookIn
			&#123;
				if not child&#40;self&#41;
				&#123;
					"The coat's pockets are empty."
				&#125;
				else
					return false
			&#125;
	 &#125;

Bainespal
Posts: 151
Joined: Fri Jul 09, 2010 8:59 am

Post by Bainespal »

I'm sorry for the delay in responding to your interesting solution here. My power's been out, and it might still be out for another day or two, so I might not be able to do much until then. Anyways, I just added your replacement routines, but I can't compile because your routines require Roodylib. I think I can probably just include the main libraries without completely installing Roodylib, but I don't really time to try it right now. I have to go somewhere, and then I'll have to charge my laptop with a generator. So, I'll play with this code when I get the chance!

As always, thank you very much. :)

[Edit] Hmm, I'm getting an error message "Maximum number of 1024 dictionary entires exceeded" after adding roodylib.g and roodylib. h.
Last edited by Bainespal on Sat Jun 29, 2013 11:11 am, edited 1 time in total.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

Since I ran into the same thing when I was trying to test something else (while still using the file I had thrown together for your problem, I tried compiling without Roodylib to see if any of the behavior was caused by it), here is an edited version of WhatsIn that should work for you:

Code: Select all

replace WhatsIn&#40;obj&#41;
&#123;
	local i, totallisted
	local initial_list_nest

	if FORMAT & NORECURSE_F
		return

	for i in obj
	&#123;
		i is not already_listed
		if i is not hidden
			totallisted++
	&#125;

	if totallisted = 0
		return

	list_count = totallisted

	if obj is not container or &#40;obj is container and obj is platform&#41; or
		&#40;obj is container and &#40;obj is not openable or
			&#40;obj is openable and
				&#40;obj is open or obj is transparent&#41;&#41;&#41;&#41; and
		&#40;obj ~= player or FORMAT & INVENTORY_F&#41; and obj is not quiet
	&#123;
		SpecialDesc&#40;obj&#41;

		! If list_count is 0 now, but totallisted was not, something must have been
		! printed by SpecialDesc


		if list_count = 0
		&#123;
			if FORMAT & INVENTORY_F and not &#40;FORMAT & LIST_F&#41; and
				list_nest = 0
			&#123;
!				print ""
				print newline
			&#125;
			return totallisted
		&#125;

			if obj.list_contents
			return totallisted

		initial_list_nest = list_nest

		if FORMAT & LIST_F
		&#123;
			if list_nest
			&#123;
				! Indent the first time so that it lines up with
				! paragraph indentation&#58;
				i = list_nest
				if list_nest = 1 and not &#40;FORMAT & NOINDENT_F&#41;
				&#123;
					Indent
					i--
				&#125;

				print to &#40;i * 2&#41;;	! INDENT_SIZE&#41;;
			&#125;
		&#125;
		else
		&#123;
			Indent
		&#125;

		if obj.contains_desc    ! custom heading
		&#123;
			if FORMAT & LIST_F
#ifset _ROODYLIB_H
				RLibMessage&#40;&WhatsIn, 1 &#41;  !  "&#58;"
#else
				"&#58;"
#endif
		&#125;
		else
		&#123;
			if obj = player
			&#123;
				if FORMAT & LIST_F and list_count < totallisted
					print "\n";

				! "You are carrying..."
				Message&#40;&WhatsIn, 1, totallisted&#41;

				if FORMAT & LIST_F
#ifset _ROODYLIB_H
					RLibMessage&#40;&WhatsIn, 1 &#41;  !  "&#58;"
#else
					"&#58;"
#endif
			&#125;
			elseif obj is living and not obj.prep
			&#123;
				! "X has..."
				Message&#40;&WhatsIn, 2, obj, totallisted&#41;
				if FORMAT & LIST_F
#ifset _ROODYLIB_H
					RLibMessage&#40;&WhatsIn, 1 &#41;  !  "&#58;"
#else
					"&#58;"
#endif
			&#125;
			else
			&#123;
				if list_count < totallisted
					! "Also sitting on/in..."
					Message&#40;&Whatsin, 3, obj&#41;
				else
					! "Sitting on/in..."
					Message&#40;&Whatsin, 4, obj&#41;
				The&#40;obj&#41;
				FORMAT = FORMAT | ISORARE_F
			&#125;
		&#125;

		ListObjects&#40;obj&#41;

		list_nest = initial_list_nest
	&#125;
	return totallisted
&#125;

Bainespal
Posts: 151
Joined: Fri Jul 09, 2010 8:59 am

Post by Bainespal »

Roody_Yogurt wrote:here is an edited version of WhatsIn that should work for you
Yes, that compiles. Thank you.

Unfortunately, the keychain still isn't being listed in inventory when inside the coat:
>i
You are wearing your coat.

>look in coat
Inside the coat's pockets is your keychain.
I did verify that the HDX file I opened was the one just compiled with your new code, so, I think something might still be conflicting somewhere.

Sorry that I don't have more time to get in to this right now.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

No worries. You'll get to it when you get to it. Just want to point out that you do also need the replaced SpecialDesc routine I listed earlier, too.

Roody_Yogurt
Posts: 2179
Joined: Mon Apr 29, 2002 6:23 pm
Location: Milwaukee

Post by Roody_Yogurt »

The main other thing I figured might be the issue was that you hadn't noticed that my coat code added the "open" attribute, which my new SpecialDesc code required for listing the contents.

Anyhow, I've talked to Kent, and it turns out I've made some bad assumptions about containers along the way. This has resulted in a new Not Dead Hugo blog post:
http://notdeadhugo.blogspot.com/2013/06 ... -code.html

and an updated SpecialDesc:

Code: Select all

replace SpecialDesc&#40;obj&#41;
&#123;
	local a, c, flag, printed_blankline

	if FORMAT & LIST_F
		return

	list_count = 0
	for a in obj
	&#123;
		if a is not hidden
		&#123;
			c++
			flag = true
		&#125;
		else
			flag = false

		if FORMAT & INVENTORY_F and obj = player and flag
		&#123;
			if &a.inv_desc
				Indent
			if a.inv_desc
			&#123;
				if FORMAT & LIST_F&#58;  print newline
				AddSpecialDesc&#40;a&#41;
			&#125;
		&#125;

		elseif a is not moved and flag
		&#123;
			if &a.initial_desc
			&#123;
				print newline
				override_indent = false
				if FORMAT & INVENTORY_F and FORMAT & NOINDENT_F and not printed_blankline
					print ""
				printed_blankline = true
				Indent
			&#125;
			if a.initial_desc
				AddSpecialDesc&#40;a&#41;
		&#125;
	&#125;
	list_count = c - list_count
	if not list_count and c
	&#123;
		for a in obj
		&#123;
			if children&#40;a&#41; and a is not quiet and
			&#40;a is platform or a is transparent or
			&#40;a is container and
			&#40;a is not openable or &#40;a is openable and a is open&#41;&#41;&#41;&#41; and
			not a.list_contents
			&#123;
				WhatsIn&#40;a&#41;
				list_count = 0
			&#125;
		&#125;
	&#125;
&#125;

Bainespal
Posts: 151
Joined: Fri Jul 09, 2010 8:59 am

Post by Bainespal »

Roody_Yogurt wrote:The main other thing I figured might be the issue was that you hadn't noticed that my coat code added the "open" attribute, which my new SpecialDesc code required for listing the contents.
Yes, that was it. Your code works well, in both wide and tall inventory listing modes. I think the aesthetics could use some work, but then, I've never been a fan of simply putting one line beneath another. I think the code as it is could be recommended on the wiki or as an extension, since this is something that could be relatively common.

I probably wouldn't have associated "open" as a requirement for inventory listing, but I have no problem using it for that purpose. Intuitiveness is fine, but practicality is even more important. If the best way to make the routine do what we need is to use the open attribute to signify being included in lists, then I think that's how to code should work.

Post Reply