Triform 1.2a New Features Over Standard Library
-----------------------------------------------
(Please read convert.txt first.)

1 Containers
2 Clothing
3 Light and Darkness
4 Printing Text
5 Actions & NPCs
6 Locks
7 Rooms & Movement
8 Scoring
9 Everything Else

== 1 Containers ==

For Containers, the (hidden_contents) array property controls whether
the Things inside/beneath/behind the Container are visible:

0	invisible until the Container is moved somehow (not inside)
1	visible but not mentioned in room descriptions (the player must
	search the Container to see them)
2	visible and mentioned in room descriptions

hidden_contents.&-->0	inside
hidden_contents.&-->1	beneath
hidden_contents.&-->2	behind

(preferred_posture) is the default posture for the Container. If the player types
STAND ON CHAIR, for example, he'll stand on the chair. But if ENTER CHAIR is typed,
the player could wind up sitting on the chair.

Every Person has a (posture) property, which can be:

1	standing (default)
2	sitting
3	lying down

IndirectlyContains() will return the (most distant) way in which the object is
indirectly contained. This means that if a passport is in a briefcase
on top of some luggage under a bed, IndirectlyContains(bed, passport) will
return 4.

0 = not indirectly contained
1 = inside
2 = on top
3 = behind
4 = beneath
5 = generically attached
6 = being held by an actor

== 2 Clothing ==

If the constant COMPLEXCLOTHING is defined, a new class Wearable
will be provided, replacing the -clothing- and -worn- attributes.

Wearables have several new properties:

layer
min_layer
max_layer
area_covered
clothing_type
covered_by
covering
conceals
gendered
manipulable_when_locked
same_layer
skirtlike
skirt_covering
skirt_layer
skirt_maxlayer
worn_by

== 3 Light and Darkness ==

If the constant NOFIRSTLOOK is provided, the initial <Look>
action will not be generated. If the NODARKNESS constant is provided,
there will never be darkness for any actor and miscellaneous
light-related code and attributes will not be compiled, making for
a somewhat smaller game file.

It is preferable now to test if two objects are visible to each
other rather than in scope to each other. Use the IsVisible()
routine to accomplish this:

	if (IsVisible(batman, joker) == true) ...
	if (IsVisible(batmobile)) ...

The order is not important, but if only one object is provided,
as in the second example, the second object will default to the
current actor. IsVisible() returns 0 if the two objects are
invisible to each other, 1 if they are visible, and 2 if they
are semivisible (see the following).

An option to implement gradual light changes has been
provided.  If the constant GRADUAL_LIGHT is defined, the
following will be compiled:

-quasilight-
-demilight-
-semilight-
-semitransparent-
DescribeQuasilight()

An object with -quasilight- can be seen in darkness,
but does not otherwise affect anything.  An object with
-demilight- will provide very faint illumination.  An object
with -semilight- provides illumination somewhere in between.
The library provides no rules for how this affects the game
other than that it will alert the player when light levels
have changed.

Anything on the other side of an object with -semitransparent-
will receive the next-lowest light level: -light- will drop to
-semilight-, etc.; -quasilight- will drop to invisibility.

When a Person carries out an action without the presence of
full light, the entry point InDarkness() is given a chance
to meddle. It may do whatever it likes and then
return either true, to interrupt the action, or false to
allow it to continue.

By default all actions are allowed in darkness except for
##Examine, ##Search, ##LookInside, ##LookOnTop, ##LookBehind,
##LookUnder, ##LookAttached, and ##Consult. To recreate the standard
library's treatment of darkness, use the following InDarkness() routine:

[ InDarkness person x;

	if (person == player) {
		if (noun == 0 || action == ##Go) x++;
		if (IndirectlyContains(person, noun) || noun == person) {
			if (action ~= ##Examine or ##Search# or #LookInside or ##LookOnTop
				or ##LookBehind or ##LookUnder or ##LookAttached or ##Consult) x++;
			else return L__M(##Examine, 1);
		}
		if (~~x) return L__M(##Miscellany, 30);
	}
	rfalse;
];

== 4 Printing Text ==

-male- and -female- can be given even to items which don't have
-animate-, and appropriate text will be generated.

You may use the past tense by using the language file
3EnglishB.h. The global variable (tense) can be:

1 for present
2 for past

You may of course switch back and forth at any time during
the game.

The property (entered_desc) has been added.  If provided, the
parser will print it instead of the generic "(in the shark tank)"
message.  For example:

	entered_desc " (trapped in Blofeld's shark tank)",

(entered_desc) may not be a routine. Note the space before the
parentheses begin.

(light_desc) has been added to handle changing the
"(providing light)" message. You might do this:

	light_desc "glowing faintly",

The (when_dark) property of rooms is used to print the description when
there is no light source. The default is "It is pitch dark in here!"

(switched_desc) has been added for the "(which is switched on)"
message, like so:

	switched_desc "powered on and humming madly",

(worn_desc) has been added for the "(which is being worn)" message:

	worn_desc "hanging off the shoulder",

Andrew Plotkin's implementation of serial commas is now supported;
simply define the constant SERIAL_COMMAS.

An Epilogue() entry point has been added, to take place between
DeathMessage() and ScoreSub(). If provided, this can produce additional
text to describe the outcome of the player's actions, rather than just
printing the death message and the score.

The optional file 3Mistype.h, which has been adapted from Cedric Knight's
original mistype.h with only minor compatibility changes, allows the
game to be forgiving of typos by the player.

== 5 Actions & NPCs ==

There are four new action properties, (middle), (react_middle), (final), and
(react_final). The two (middle) properties are called after the action has been
determined to be possible but before it is carried out. The final properties
take place after the action has been carried out and messages printed.

The two-entry array cant_touch_reason stores the reason that an object
could not be touched, heard, or smelled. cant_touch_reason-->0 stores the objec
that is blocking the action. cant_touch_reason-->1 stores the reason:
	1 = the object must be opened
	2 = the actor must exit the object
	3 = the actor must disrobe the object
	4 = it is being held by another actor

The optional file 3Reach.h provides a simplistic way to implement reachability
rules.

If you would like to have an action occur silently, without printing up any
library messages regardless of success or failure, simply set the global
variable keep_silent to 2.

When taking INVENTORY, items inside a closed opaque container will be listed if they have
-topic- (on the presumption that this means the player knows they are there).

To implement the inventory change, two changes were made to the handling of WORKFLAG_BIT.
First, it now applies at all depths and not only the top level. Second, WORKFLAG_BIT now
takes precedence over CONCEAL_BIT.

And on a minor note, the behavior of 'REMOVE XXX' has been slighty altered.
If the noun is not a child of the player, it will generate a TAKE action
rather than a DISROBE action.

If an action is unsuccessful, the library will set the global variable failed_action
to the library message number printed in response. For example, if the player tries
to open something that is locked, then failed_action will be set to 2.

A multiple-object action (e.g. TAKE ALL COINS) can be stopped cold by setting
failed_action to -1.

Every NPC has an npc_number property that the game will automatically set up at the
start, unless set manually.

It's now very easy to have NPCs perform any action that the player can.
Simply call <action noun second, actor> or <<action noun second, actor>>.
NPC actions will not advance the clock and you may call as many of them
per turn as you like.

Here's a very simplistic example of an NPC who opens a bag, takes a coat,
and then puts it on, on consecutive turns.

	each_turn
	[; if (bag hasnt open)
		<<##Open bag 0, self>>;
	   if (coat notin self)
		<<##Take coat 0, self>>;
	   if (coat in self && coat.worn_by == 0)
		<<##Wear coat 0, self>>;
	],

The returns simply prevent all of these acts from occurring in the same turn.

Defining the constant TRACK_LOCATIONS before the inclusion of 3Parser will enable the
use of a method for tracking the last time the player and each NPC (up to 32) saw each
game object. This is accomplished using the properties last_seen and last_seen_npc.
last_seen is a four-entry array:
last_seen-->0 == the location the item was seen by the player
last_seen-->1 == the parent of the item at that moment
last_seen-->2 == the IndirectlyContains() result for the item at that moment
last_seen-->3 == the time or turns value at that moment

last_seen_npc is simpler. It is a 32-entry array, one entry for each of up to 32 NPCs.
Each entry stores the location an item was last seen by the npc with the corresponding
npc_number property. For example, if Paul's npc_number is 0 and he last
saw the precious jewel in his office, then precious_jewel.&last_seen_npc-->0 == office.

Finally, the optional library 3goals.h provides an engine for NPCs to set up plans and
act independently to achieve defined goals. Its documentation is in its file.

== 6 Locks ==

A more complicated system for keys and locks is available. If the player attempts to
lock or unlock something, there are two possibilities: she has either not specified any key,
or else she has specified something to use as a key. In the first case the Lockable item's
with_key routine is consulted to aid in inferring a possible key. In the second case the
with_key property is consulted to test the success or failure of using this particular key.

with_key can return:

-1: Never auto-try any key.

0: This item is obviously not a key and should not be tried.

1: This item is a key, but does not unlock this item.

2: This item is the correct key, but the actor does not know it is the correct key.

3: This item is not the correct key, but appears to the actor to be a better guess
than one which returns 1 or 2.

4: This is the correct key, and is a better guess than one which returns 1 or 2.

5: This is the correct key, but does not appear to be a key at all.

6: This is the correct key, and the actor knows it to be the correct key.


For example, imagine a treasure chest and three keys: gold, silver, and bronze. The player
does not know which key unlocks the chest. The correct key is the gold key, but inspection
of the chest shows it to have a silver lock. Thus until the player discovers that the
gold key is the correct one, the silver key will be tried first:

Container treasure_chest "treasure chest" class Lockable,
with 	name "chest", adjective 'treasure',
	with_key
	[ obj;
		switch (obj) {
			gold_key: if (self.gold_key_tried) return 6; else return 1;

			silver_key: if (self.gold_key_tried) rfalse; else return 2;

			bronze_key: if (self.gold_key_tried) rfalse; else return 1;

			default: rfalse;
		}
	],
	inside_capacity 5,
	locked true,
	gold_key_tried 0,
	silver_key_tried 0,
	bronze_key_tried 0,
	description "It has a silver lock.";
	after
	[; Lock, Unlock:
		if (second == gold_key && ~~self.gold_key_tried) self.gold_key_tried = 1;
	],
has	openable;


with_key can still be a single object or 0. If 0, no key at all is necessary to lock or
unlock the object. It may also be set to -1 if you do not want the game to try keys
at random:

Container cupboard "cupboard" class Lockable,
with	name "cupboard",
	with_key -1,
	before
	[; Lock, Unlock:
		if (self.with_key == -1 && second == cupboard_key)
			self.with_key = cupboard_key;
	],
has	openable;

== 7 Rooms & Movement ==

Rooms have a number of new features. An (after) routine can now react to
an actor leaving. The ##GoneFrom fake action is provided for this:

after [; GoneFrom: if (actor == player) print "You walk out of the kitchen.^"; ];

Checking that actor == player is necessary because otherwise NPCs moving
about could trigger the message.

When the player witnesses NPCs moving about via ##Go actions (probably through
NPCAction() calls), the library will print up suitable messages. The content
of these messages depend on whether the Room which the NPC enters/leaves has
been visited by the player already or not. If it has not, the message may be
"The mysterious man walks in from the north." If it has, the message may be "The
mysterious man walks in from the garden."

Rooms also have (travel_name) properties. This allows you to alter those
messages. Thus, the garden's (travel_name) could change from "garden" to
"trampled garden". By default the (travel_name) is blank, in which case the
message might be "The mysterious man walks in from the Garden."

(cant_go) can now be a routine, allowing for more complex behavior. So you
could do something like this:

  cant_go [; if (noun ~= u_obj) "The ladder is the only safe way out."; ],


The optional file 3Pathmaker.h, adapted from Jim Fisher's code, provides a way
to calculate paths between rooms, or between objects.

== 8 Scoring ==

Roger Firth's suggestion for negatively-scored achievable tasks has been
implemented. This means that task_scores must be created as a word array, e.g.:

Array task_scores --> 2 2 (-1) 8;

It's also easier to set up partially achievable scored tasks. To do so,
set up something like this:

Array task_scores --> 0 0 0 0;

[ PrintTaskName task_number;
  switch (task_number) {
	0:
	switch (task_scores-->0) {
		10: "this task is complete";
		default: "this task has been partly completed";
	}
	1:
	switch (task_scores-->1) {
		7: "this task is complete";
		default: "this task has been partly completed";
	}
	2: "this task is complete";
		
	3: "this task is complete";
  }
];

Then, in your Initialise() routine, put the following lines:

  notify_mode = 2;
  for (i=0 : i<NUMBER_TASKS : i++) { task_done->i = 1; }

The first line tells the library that you want to allow partially
achievable tasks. The second line is necessary if you want such
tasks to be listed in the full score even if they have not yet
been begun. Obviously you may need to adapt it to your game.

== 9 Everything Else ==

Adjectives are available. Just give your Things (adjective)
properties, like so:

Thing denim_jacket
with	name "jacket", adjective 'blue' 'denim' 'jean',

You must use single quotes for adjectives.  Note also that
adjectives are weak--one can't, in the above example, simply
type LOOK AT DENIM and get a description of the jacket. Also,
in order to be recognized by the parser they must come before
the entries in the (name) property, so that LOOK AT DENIM JACKET
will work but not LOOK AT JACKET DENIM.

If the constant CHARACTER = XXX is provided, the selfobj
will not be compiled.  Additionally, you will not have to provide
the line "ChangePlayer(XXX)" in your Initialise() routine.

The -anatomy- attribute, intended for body parts,
has been added. An object with -anatomy- will not
be included in inventory descriptions nor count against
an actor's (capacity) property (as long as its
(attachedtoparent) property is true, because, after all,
grisly things may occur).

In debugging mode, the TREE command produces slightly more complete text when
listing the states of objects -- for example, "(which is closed and locked)".

The library keeps track of the actions most recently performed by all actors.
Every Person has a (last_action) property, which is an array with three entries. The
first entry contains the action; the second the noun (if any); and the third contains
the second (if any).

You can define a constant NO_MENUS (before including 3Parser) to prevent the compilation
of the default method for creating menus. If you don't use menus this will save some
memory.

ObjectIsUntouchable() may be applied to anyone, not just the current actor. It must be called
as ObjectIsUntouchable(item, person, flag1, flag2, flag3).

Setting (failed_action) to -1 will interrupt a multiple action. This is currently
used to interrupt a PUT ALL action that has no further chance of succeeding
because the object to be filled is already full.

last_seen->0 = the Room
last_seen->1 = the parent
last_seen->2 = the parent relationship
last_seen->3 = the time

By default, the LibraryExtensions object will not be compiled. If your game uses it, define the
constant USE_LIBRARY_EXTENSIONS before 3Parser.h. Generally, LibraryExtensions is updated to
include the additional functionality in standard Library 6/12.

Finally, the optional library 3Who.h provides a way for the player to ask questions about the
game world, whether to NPCs or to the narrator.