[I6] Wearing or removing multiple items of clothing at once

As I review bug reports for the Inform6 Standard Library, I have one that complains that WEAR and DISROBE do not allow for the player to wear or doff multiple items at once. Is there a historical reason for this? Is it a good idea to allow for actions like WEAR ALL, WEAR HAT AND COAT and TAKE OFF HAT AND COAT?

2 Likes

Wearing and disrobing dress is one entry point into the dark realm of creeping featurism… (I read it on DM4 or CoA, don’t remember now which) so, generally, moderation in implementing wearing was (intentionally ?) encouraged.
But one puzzle I fondly remember is one about perfectly disguising as uniformed deliveryman…

OTOH, I’m toying with a concept I call “moonmist dress”, that is, choosing a dress instead of a favorite colour at start (pls don’t start a mimesis debate on Moonmist…)

Best regards from Italy,
dott. Piergiorgio.

Usually complicated clothing and undressing mechanics only figure in for adult games, and most of those authors are familiar with creating their own systems with overlapping clothing layers and specifically exposed and unexposed anatomy. There is a very complicated layered clothing example in the documentation that usually serves as the template.

Most non-AIF usually either disregards physical clothing completely, assuming the player is dressed appropriately through the entire game and only wearing special items like the “amulet of invisibility” or “the ring of confidence”, or often will implement complete outfits, say if a player has to dress differently for work or social activities.

Personally I think clothing mechanics can be very tedious in games that aren’t about making a fashion statement as gameplay. When I’ve done it I have made UNDRESS or DISROBE mean “take off everything” in sequence, and TAKE OFF [GARMENT] do it piecemeal. Usually it’s easier to implement full outfits as one garment instead of separate trousers, underwear, undershirt, blouse, skirt, left shoe, right shoe, left sock, etc.

I recommend making it easy as possible for the player if you’re doing an adult game or an implementation of The Devil Wears Prada and clothing combinations are essential to the plot!

1 Like

It’s worth noting that the only verbs in the standard library that accept plurals are TAKE, DROP, PUT, and REMOVE (in the obscure sense of “remove treasures from case”.)

I don’t remember if the the DM4 discusses the reasoning behind this. But I’d say it comes down to multiple actions being inherently a bit fragile. It’s hard enough to plan your game logic when only one thing can happen in a turn; multi-object actions require extra planning, plus (really) some extra logic to decide when to interrupt the sequence of actions. Inform doesn’t really give the author enough support to make this routine. So the library takes the safe route and keeps everything singular except for the few actions needed for routine inventory juggling.

3 Likes

I looked up, and is in ch. III para 11:

▲ A risk of providing clothing for the player is that it’s hard to resist the lure of realism. A tweed jacket would add some colour to ‘Ruins’. But if a jacket, why not plus-four trousers, an old pair of army boots and a hat with a mosquito net? And if trousers, why not underwear? What are the consequences if the player strips off? Too much of this kind of realism can throw a game off balance, so: no tweed.

Best regards from Italy,
dott. Piergiorgio.

The standard library made some very poor choices in the early days and most of us have been devising workarounds for this ever since. In the case of clothing, the property name itself was a bad choice. It should have been wearable, as not everything that can be worn is clothing. For example, you can wear a ring and a backpack, but these are not clothing.

I suspect that the lack of support for WEAR ALL and REMOVE ALL is because of the layering that sometimes comes into play with clothing as aluded to in @Piergiorgio_d_errico’s quote from the DM4. To take the simple example of a shirt and a jacket, if you start topless, you can wear the shirt or the jacket and you can put the jacket on over the shirt, but you can’t put the shirt on over the jacket. The author currently has a choice on how to handle this:

  • You can allow it regardless, even though it doesn’t make sense in real life.
  • You can do an implicit removal of the jacket, then wear the shirt and tell the player “(first removing the jacket)”.
  • You can tell the player that the shirt won’t fit over the jacket.

When doing a (hypothetical) WEAR ALL or REMOVE ALL, you have no control over the order in which clothing items are worn or removed. If the author has before rules to account for the 2nd or 3rd cases above, you could get a response like this:

>WEAR ALL
Jerry can: You can't wear that.
Jacket: You put on the jacket.
Shirt: (first removing the jacket)
You put on the shirt.

And you’re left with an unworn jacket.

There will be cases where the sequence is important to the game and may be part of a puzzle, so I think, in this case, it is better to keep it simple unless you’re prepared to build some smarts into the library.

In retrospect, maybe you could allow it and let the author’s ChooseObjects routine decide what can be worn or removed. Something like (untested):

[ ChooseObjects obj code;
  if (code == 2)
  {
    ! Stage 1: Disambiguation stuff
  }
  ! Stage 2: Processing an "all"
  if (obj has scenery or concealed or static or animate)
    return 2; !Force exclusion
  if (action_to_be == ##Wear && obj notin player && obj has clothing)
    return 1; !Force inclusion
  if (action_to_be == ##Disrobe && obj in player && obj has worn)
    return 1; !Force inclusion
  return 0; !Accept parser's decision
];

EDIT: I had ##Remove in the above routine. It should have been ##Disrobe. Now corrected.

Do I need to do anything to the library to make this easier?

I have written a little test program. I have added one non-clothing item (a jerry can) and six clothing items: shirt, singlet, pants, underpants, shoes and socks. I have assumed that the shirt goes over the singlet, so you can’t wear or remove the singlet if the shirt is already worn. Similarly, you can’t wear or remove the underpants if the pants are worn and you can’t wear or remove the socks if the shoes are worn. In addition, you can’t wear or remove the pants or underpants if the shoes are worn. These are all pretty reasonable assumptions and are handled by before routines.

As wear and remove clothing are normally defined with held tokens in the grammar, I extended the grammar with a multiheld token.

After a lot of experimenting, I had to use a ChooseObjects routine to forcibly include or exclude items when processing an ALL. The end result is about as good as you’re going to get. WEAR ALL and REMOVE ALL work as expected, both with and without implicit actions, it doesn’t try to wear or remove anything stupid and the before routines are honoured. Obviously, if you don’t have any before routines, there are no restrictions and you can wear and remove anything that has a clothing attribute.

The code is included below. As to whether you need to do anything to the library, you could perhaps replace the held token with the multiheld token and make sure that the library’s WearSub and DisrobeSub handle the conditions tested for in ChooseObjects so that a custom ChooseObjects is not necessary. Otherwise, do nothing and let authors do it manually as I’ve done here.

Constant Story "Wear All";
Constant Headline "^An interactive experiment^^";

Include "parser";
Include "verblib";

[ Initialise;
!  no_implicit_actions = true;
  location = test_lab;
  "This is a test of wearing and removing multiple objects in the one command, such as WEAR SHIRT AND PANTS or REMOVE ALL.";
];

Object test_lab "Test Lab"
with
  name 'test' 'lab',
  description "You're in the test lab.",
has light;

Object can "jerry can" test_lab
with
  name 'jerry' 'can',
  description "It's a WW2 vintage jerry can.",
has;

Object shirt "shirt" test_lab
with
  name 'shirt',
  description "It's a very colourful Hawaiian shirt.",
has clothing;

Object singlet "singlet" test_lab
with
  name 'singlet',
  description "It's a white singlet.",
  before
  [;
    Disrobe, Wear:
      if (shirt has worn)
        "You'll have to take the shirt off first.";
  ],
has clothing;

Object pants "pants" test_lab
with
  name 'pants',
  description "It's a cheap pair of grey-brown pants that you bought from Lowes.",
  before
  [;
    Disrobe, Wear:
      if (shoes has worn)
        "You'll have to take the shoes off first.";
  ],
has clothing pluralname;

Object underpants "underpants" test_lab
with
  name 'underpants//p',
  description "underpants//p",
  before
  [;
    Disrobe, Wear:
      if (pants has worn)
        "You'll have to take the pants off first.";
      if (shoes has worn)
        "You'll have to take the shoes off first.";
  ],
has clothing pluralname;

Object socks "socks" test_lab
with
  name 'socks//p',
  description "It's a pair of woollen socks.",
  before
  [;
    Disrobe, Wear:
      if (shoes has worn)
        "You'll have to take the shoes off first.";
  ],
has clothing pluralname;

Object shoes "shoes" test_lab
with
  name 'shoes//p',
  description "It's a pair of leather shoes.",
has clothing pluralname;

[ ChooseObjects obj code;
  if (code == 2)
  {
    ! Stage 1: Disambiguation
    if (action_to_be == ##Take && obj notin player)
      return 1; !Appropriate
    if (action_to_be == ##Drop && obj in player && obj hasnt worn)
      return 1; !Appropriate
    return 0; !Inappropriate
  }
  ! Stage 2: Processing an "all"
  if (obj has scenery or concealed or static or animate)
    return 2; !Force exclusion
  if (action_to_be == ##Take && obj ~= player && obj notin player)
    return 1; !Force inclusion
  if (action_to_be == ##Drop && obj in player && obj hasnt worn)
    return 1; !Force inclusion
  if (action_to_be == ##Wear && obj hasnt clothing)
    return 2; !Force exclusion
  if (action_to_be == ##Wear && obj hasnt worn)
    return 1; !Force inclusion
  if (action_to_be == ##Disrobe && obj has worn)
    return 1; !Force inclusion
  if (action_to_be == ##Disrobe)
    return 2; !Force exclusion
  return 0; !Accept parser's decision
];

Include "grammar";

Extend 'remove' first
  * multiheld -> Disrobe;

Extend 'wear' first
  * multiheld -> Wear;

End;

Actually, I think REMOVE ALL would work. Every object has a linked list of children. When a new child is added (e.g. an object is worn), it is inserted at the front of the list. Thus, when traversing the children (e.g. as part of an object loop due to ALL), they will be encountered in reverse order, compared to how they were added. So as long as the player is prevented from wearing the socks after the shoes, REMOVE ALL will never attempt to remove the socks before the shoes.

The point about WEAR ALL remains.

If you do a WEAR ALL immediately followed by a REMOVE ALL, I think you’re right, but if you remove individual items in order to wear the things that failed when you did a WEAR ALL, and then wear the things that you just removed until you’re wearing everything and then do a REMOVE ALL, it fails again on certain items depending on the structure of the tree. You can try it in the little demo game I posted. It’s standalone, so you can copy, paste and compile.

You then remove the * multi -> Take from the verb remove, otherwise it conflicts with * multiheld -> Disrobe;

Verb 'remove'
    * multiheld                              -> Disrobe
    * multi                                  -> Take

And you don’t put multiheld to the verb disrobe:

Verb 'disrobe' 'doff' 'shed'
    * held                                   -> Disrobe;