cfad47cfa3/t3compiler/tads3/lib/adv3/to_do.txt

4b825dc642cb6eb9a060e54bf8d69288fbee4904cfad47cfa334b206c65f22086bcc5d63e6f70944
1
================================ VERSION 3.0 =================================
2
3
================================ VERSION 3.1 =================================
4
5
**** COMMITTED CHANGES - the following are changes that we've
6
definitely decided to make, but which we've deferred until after the
7
next general release because it's too late in the current release
8
cycle to make changes that could be potentially destabilizing.
9
10
1. In DefineTAction(TravelVia), remove the override for
11
getCurrentObjects.  This override was originally put in place because
12
the direct object of a TravelVia is a TravelConnector, which was at
13
one time based on 'object' rather than on Thing.  TravelConnector is
14
now a Thing subclass, so the direct object of a TravelVia will always
15
be a simulation object, hence it's fine to return it as an action
16
object.
17
18
2. In RestrictedUnderside, RestrictedRearContainer, and
19
RestrictedRearSurface, the iobjFor(PutXxx) check() routine should call
20
"inherited Xxx()" (where Xxx is the unrestricted base class - the
21
*second* base class in the RestrictedXxx superclass list) to enforce
22
the inherited allowPutXxx restriction.  However, we can't just add the
23
'inherited' call: each of the base container check() methods does a
24
simple reportFailure(&cannotPutXxxMsg), whereas the Restricted classes
25
invoke self.cannotPutXxxMsg(dobj) - same method, different argument
26
list.  We either need to rename the cannotPutXxxMsg(dobj) version of
27
the method, OR add the dobj parameter to the parameter-less form of
28
the method.  In either case, we could break some existing code.  I
29
think the renaming approach is probably better, because there really
30
are two failure conditions here.
31
32
The lowest impact approach is probably to change cannotPutXxxMsg(obj)
33
to something like cannotPutObjXxxMsg(obj) for all of the various
34
RestrictedXxx containers.  This will necessitate a little global
35
search and replace for existing code, but the alternative is to change
36
some much lower level code: the no-parameter cannotPutXxxMsg messages
37
are used in Thing, for instance.
38
39
40
41
**** REQUESTED CHANGES - the following are changes that have been
42
suggested and possibly discussed to some extent on the tads3 mailing
43
list, but whose final disposition is yet to be determined.  We might
44
or might not ultimately decide to add any of these features.
45
Priorities, feasibility, and full design details are yet to be
46
determined for many of these.
47
48
49
---------
50
51
From Eric Eve <eric.eve@harris-manchester.oxford.ac.uk>: In the adv3
52
command execution sequence, the relative ordering of the "check" phase
53
and the various "before" notifications seems wrong as it currently
54
stands.  Currently, "before" happens before "check" - this means that
55
the command can fail in the "check" after the "before" notifications
56
have occurred.  Conceptually, it seems like "before" notifications
57
should only occur after the action is committed.  Now, this isn't
58
truly possible in practice, because any individual "before" handler
59
could still cancel the whole command - the relative ordering of
60
"before" handlers is arbitrary, so a "before" handler could cancel the
61
action after other "before" handlers already ran.  Nonetheless, it
62
probably makes sense to consider "check" as a stronger sort of test
63
than "before"; it's relatively rare for "before" handlers to cancel a
64
command, while testing for cancel-worthy conditions is the whole point
65
of "check."
66
67
Implementing this change is trivial.  The only reason for putting this
68
off until 3.1 is that it seems likely to break a small amount of
69
existing code - most code won't be affected at all, but there will
70
probably be a few existing cases that depend subtly on the existing
71
ordering due to interactions among multiple objects and/or handlers.
72
People are more likely to expect and accept this sort of compatibility
73
risk in a major update.
74
75
76
---------
77
78
From Michel Nizette <mnizette@ulb.ac.be> [9/1/06]:
79
80
Would there be any value in implementing pending conversations via
81
regular AgendaItems, like we just did for the boredom handling?
82
Again, the advantage would be simply to provide more control over the
83
order of priority of an actor's various pending activities.  Also,
84
should this prove useful, we could then think of adding an
85
Actor.scheduleConditionalInitiateConversation method, which would do
86
the same thing as scheduleInitiateConversation, but would additionally
87
specify an extra condition to be checked as part of the AgendaItem's
88
isReady property.  The condition could be specified simply as a
89
callback function that returns nil or true. 
90
91
---------
92
93
From Michel Nizette <mnizette@ulb.ac.be> [9/1/06]:
94
95
Currently, the method Actor.noteConversation is invoked each time a
96
TopicEntry is triggered, no matter if the topic is conversational or
97
not (i.e., marked with isConversational = true or nil).  The
98
noteConversation method does a number of things like marking the actor
99
as having conversed on the current turn, and resetting the boredom
100
count.  But I'm wondering if this is really what we want in the case
101
of a non-conversational topic, whose typical purpose is to describe a
102
refusal to engage in a particular conversation.  If the conversation
103
doesn't actually take place, should there really be any effect on the
104
NPC's behavior?  It would seem a little odd to see an NPC delaying a
105
pending conversation for several turns just because he was involved in
106
a sequence of conversational commands that all got blocked in the PC's
107
mind for motivational reasons and didn't result in a real dialogue,
108
for example. 
109
110
In contrast, noteConversation also does a few things that
111
unquestionably make sense for non-conversational topics, like updating
112
pronouns and establishing a default interlocutor: these are interface
113
features independent of what happens in the game world. 
114
115
So, my suggestion would be to distinguish between the situation where
116
a conversation actually takes place (in which case it makes sense to
117
call noteConversation) and the situation where the conversation is
118
only attempted, which we could handle via a new
119
noteAttemptedConversation method that would only set pronouns and the
120
default interlocutor.  The library could then simply invoke
121
noteAttemptedConversation everywhere it currently invokes
122
noteConversation, and could additionally call noteConversation in the
123
few places where a real conversation takes place, like the triggering
124
of a conversational topic or a call to Actor.initiateConversation.  If
125
maintaining backwards compatibility is important, we could have
126
noteAttemptedConversation call noteConversation by default, but we
127
could make this controllable via a switch. 
128
129
---------
130
131
From Krister Fundin <fundin@yahoo.com> [9/3/06]:
132
133
> bob, follow me
134
"Okay, I will follow you."
135
> g
136
"Okay, I will follow you."
137
138
The library comments suggest that the latter should not happen. The
139
problem is that Actor.nonIdleTurn() cancels following whenever the
140
actor receives an order. Thus the check for already being in following
141
mode is always negative.
142
143
[mjr: I actually think the current behavior as shown is fairly
144
reasonable.  It would be marginally better to have a message like "I'm
145
already following you."  But short of repeating the command ten times
146
in a row for comic effect, I'm not sure players would ever be bothered
147
by the present behavior in practice - if they're repeating the command,
148
they're presumably not sure that Bob was already in follow mode, so
149
they're not going to be bothered by another acknowledgment.]
150
151
I had already removed this cancellation from one of my projects, since
152
it wasn't appropriate there, but that seems to cause a different
153
problem instead:
154
155
> bob, follow me
156
"Okay, I will follow you."
157
> g
158
Nothing obvious happens.
159
160
In this case, Bob can already see the player and thus only makes a
161
call to checkMovingActorInto(), which does nothing since he's already
162
where he's supposed to be.
163
164
[mjr: This part is worth looking into whatever the disposition of the
165
first part, since the nonIdleTurn() comment suggests that it's okay to
166
override and not cancel follow mode, but apparently that's
167
problematic.]
168
169
---------
170
171
From Krister Fundin <fundin@yahoo.com> [9/3/06]:
172
173
just a thought (feel free to ignore it):
174
175
> bob, follow me
176
"Okay, I will follow you." Bob stands on the main platform.
177
178
versus:
179
180
> bob, follow me
181
Bob stands on the main platform. "Okay, I will follow you."
182
183
Doesn't the latter sound marginally better? 
184
185
[mjr: I'm not sure about this; Bob acknowledging first actually strikes
186
me at the moment as the better sounding version]
187
188
I guess in practice there would be a command separator between the two
189
reports, but that could actually improve things when two or more
190
implicit actions are needed:
191
192
> bob, follow me
193
"Okay, I will follow you." Bob stands on the main platform.
194
195
Bob stands on the red platform.
196
197
versus:
198
199
> bob, follow me
200
Bob stands on the main platform.
201
202
Bob stands on the red platform.
203
204
"Okay, I will follow you."
205
206
---------
207
208
From Krister Fundin <fundin@yahoo.com> [9/8/06]:
209
210
How about adding a command joiner report and corresponding pseudo-tag?
211
Any combination of joiner and separator or separator and joiner would
212
just remove both. I can think of a few other places where I could use
213
one of those.
214
215
[i.e., something like <.commandjoin> to cancel out <.commandsep>]
216
217
---------
218
219
From Krister Fundin <fundin@yahoo.com> [9/13/06]:
220
221
   > push television into white box
222
   (first standing on the main platform)
223
   Okay, you're now standing in the white box.
224
225
Perhaps it's not serious enough that it needs to be fixed now. In the
226
long run, one could imagine a "first trying to push the television
227
onto the main platform" type of implicit action here, but that would
228
take some work.
229
230
[I'm not even sure what would be right here.  I guess some
231
fine-grained variation of PushTravel for pushing into nested rooms or
232
something.]
233
234
---------
235
236
The ThingState mechanism should be extended to allow a single object
237
to have multiple current, active states.  For example, it should be
238
possible for an object to be simultaneously worn, lit, and open.  As
239
it stands, an object can only have one state at a time.
240
241
On the parsing side, this is straightforward: we simply have to
242
iterate over the list of active states and consider each one's token
243
selectivity in turn.  All active states must rule positively on the
244
token list to allow a match.
245
246
On the output side, it's slightly more work.  We'll have to list
247
multiple states in messages like "(providing light)", which isn't
248
hard: "(worn, open, providing light)".  We'll also have to list
249
multiple states in sublists: "one worn, open, and providing light; one
250
closed."  This is also relatively straightforward except that we'll
251
have to go to semicolons in the overall list when the sublists start
252
expanding out to the point that they need commas.
253
254
(Ideally, ThingState probably ought to be the *only* state mechanism
255
for any sort of state for which it's used.  For example, there really
256
shouldn't be a separate isOpen property - an object's open/closed
257
status instead ought to be determined by the presence of an openState
258
or closedState object in the object's state vector.  Opening an object
259
would then be a matter of calling obj.setState(openState).  This would
260
require that each ThingState know its set of states, for mutual
261
exclusion when a new state is set (which would simplify things
262
slightly in that we'd be able to dispense with the per-object
263
allStates list.)
264
265
(Also ideally, ThingState sets would implicitly and automatically
266
create distinguishers.  Any time we have a pair of objects with
267
different active states from a given set, we should automatically be
268
able to distinguish those objects on the basis of that ThingState
269
set.)
270
271
---------
272
273
In announceAmbigActionObject, announceMultiActionObject, and
274
announceDefaultObject, it'd be ideal to use distinguishers to decide
275
on the object name.  This would ensure, for example, that we generate
276
"(the lit candle)" when litness would distinguish the candle we chose
277
from others present.  
278
279
I think we'd basically have to do the same work that
280
BasicResolveResults.ambiguousNounPhrase does to choose a distinguisher,
281
but in this case we want to tell apart the object in question from
282
everything else in scope that has the same name.  So, probably we want
283
to go through the objects in scope and build a list of everything
284
with the same disambigName; then we want to search for a distinguisher
285
that can tell apart the object in question from all of those other
286
objects; failing that, we could settle for a distinguisher that can
287
tell apart the object in question from any of the other objects, as
288
this would provide at least some greater specificity.  Failing that,
289
we just use the disambigName.
290
291
---------
292
293
Consider removing several modules from adv3 and putting them in the
294
"system" library instead:
295
296
  banner.t
297
  menusys.t
298
  modid.t
299
  numbers.t
300
301
---------
302
303
Add a property setting that makes the contents of an item listed
304
immediately after the item's specialDesc, if it's using a specialDesc.
305
The contents would be listed there rather than in the miscellaneous
306
portable list paragraph.
307
308
---------
309
310
Add static File.deleteFile(filename), to delete a file from disk.
311
This operation should require WRITE privileges (as determined by the
312
file safety level setting) for the given file.
313
314
---------
315
316
Add a version of saveGame() and restoreGame() that use a ByteArray as
317
the saved state medium.  save() would create and return a new
318
ByteArray object containing the saved state (which must, of course,
319
exclude the new ByteArray itself); restore() would take a ByteArray
320
object and restore its contents as the current game state.
321
322
For interface purposes, we could simply let saveGame() without an
323
argument return a ByteArray, and restoreGame() could take a ByteArray
324
as its argument.  Alternatively, saveGame() could take a pre-created
325
ByteArray as its argument, and we'd fill in that ByteArray with the
326
saved state (but we'd somehow have to make sure that this ByteArray
327
was excluded from the saved state).
328
329
(Implementation note: this is fairly straightforward, but some work.
330
We first have to refactor CVmFileSave::save() and restore() to take
331
CVmStream objects instead of CVmFile objects; this is fairly simple,
332
but requires changes down through the whole save/restore stacks, which
333
touch a lot of objects.  Then, where we currently call save/restore
334
with CVmFile objects, wrap the CVmFile in a CVmFileStream and make the
335
same call.  Finally, we'd have to create a new CVmStream subclass that
336
operates on ByteArray objects, which should be a fairly easy mapping.
337
It'd be worth making sure that changing CVmFile to CVmStream in
338
save/restore doesn't balloon up the executable too much - this would
339
introduce a ton of new virtual calls, because all of the CVmStream
340
methods are virtual while the corresponding CVmFile methods are
341
non-virtual.  It'd also be worth measuring any degradation in
342
save/restore performance from all the new virtual calls.)
343
344
---------
345
346
Store ALL objects as potential future pronoun antecedents when
347
processing a multi-object command.  For example, when executing UNLOCK
348
DOOR WITH KEY, store *both* the door and the key as potential
349
antecedents for 'it'.  On using 'it' in a future command, look at all
350
of the possible antecedents, and choose the most logical one -
351
essentially treat the set of possible antecedents as though it were
352
the set of matching objects for an indefinite noun phrase.  If there's
353
more than one equally logical choice, choose one arbitrarily, the same
354
way we would if the player typed TAKE ANY BOOK:
355
356
>unlock door with key
357
Unlocked.
358
359
>drop it
360
Dropped.           // refers to the key, since the door is illogical for DROP
361
362
...but if the next command were this instead:
363
364
>open it
365
Opened.            // refers to the door, since the key is illogical for OPEN
366
367
...and if it were this instead:
368
369
>x it
370
(the door)             // both door and key are equally logical, so choose
371
It's a massive...      // one arbitrarily, and report the choice
372
373
---------
374
375
Debugger: display the current method (the top of the stack trace) in
376
the status line.
377
378
---------
379
380
Debugger: add an option to skip over library code when stepping.  This
381
could be a mode, or it could be a new 'step' command (alongside 'step
382
in', 'step over', 'step out').  This would make it easier to isolate a
383
bug in game code, and it would also clarify the control flow through
384
the sequence of game-provided entrypoints.
385
386
The main question in implementing this is how exactly to define
387
'library' code for the purposes of this new form of stepping.  Library
388
code could be defined as anything from a .tl file, or as any source
389
file under the system directory tree, or as files designated as such
390
manually (with a right-click on a file in the project tree, say).
391
392
---------
393
394
Can we rephrase the UNDO command results so that they reflect the logical
395
command rather than the actual text typed in?  Something like:
396
397
 >undo
398
 Taking back: attack the troll with the sword
399
400
(For commands involving multiple objects, this could get cumbersome, since
401
we probably wouldn't be able to easily reconstruct the original ALL or
402
plural usage, but would instead list all of the objects.)
403
404
---------
405
406
Maybe use <.Q> rather than <Q> in msg_neu and en_us, to allow customization
407
of quote styles.
408
409
---------
410
411
Add a global compiler options setting to workbench?
412
413
---------
414
415
The compiler should flag some types of errors at the location of the
416
particular token causing the error, rather than at the location of
417
the enclosing source line.  Krister Fundin <fundin@yahoo.com> pointed
418
this out with respect to an expression like this, where the 'method'
419
name is undefined:
420
421
   property.method(new function(x)
422
   {
423
        code;
424
   });
425
426
The error ought to be reported at the exact line containing the
427
undefined token 'method', rather than at the statement level - which,
428
in this case, reports at the *end* of the nested function.
429
430
To accomplish this, the compiler would have to (a) save the source
431
location for each individual token, in addition to the location of the
432
current statement; and (b) use the token location rather than the
433
current line when reporting any error that can be associated with a
434
token.  [The second part is probably pretty easy - almost all such
435
cases can probably be caught by changing
436
CTcTokenizer::log_error_curtok() to report at the current token
437
position.  Saving the token position probably isn't too hard, either,
438
but there might be some subleties, such as with respect to the
439
preprocessor.]
440
441
---------
442
443
Add a general "warning check" mechanism to the library.  This would
444
be an add-on module that would encapsulate a bunch of checks for
445
common pitfalls, using reflection mechanisms to display warnings.
446
Authors could optionally compile with this module from time to time
447
to check for common errors.  This would only be of interest to
448
authors during development, of course - it would always be removed
449
for the final build for release.  (This came up in the context of
450
checking for default Container objects when using the liquid add-on
451
library.  It would be nice to have a generic mechanism, or at least
452
some coding patterns to follow, that would simplify adding this kind
453
of warning check.)
454
455
---------
456
457
For ResolvedTopic, it might be nice to ask for disambiguation for
458
in-scope objects if there are more than one, especially if this were
459
parameterized.
460
461
---------
462
463
Menu-based conversation framework
464
465
---------
466
467
For travel, add a check to see if the actor fits through the passage.
468
This should ideally be implemented using a precondition that would
469
check the actor's bulk to ensure it's below a maximum.  The actor
470
would have a chance to reduce its bulk via a tryReducingBulk call,
471
perhaps - this would let the actor do something obvious like close
472
an umbrella.
473
474
---------
475
476
For travel, add a check for excessive encumbering bulk or weight.
477
This could be used for things like climbing ropes or walking across a
478
rickety bridge.  For excessive encumbrance, the actor could use the
479
standard tryMakingRoomToHold mechanism to reduce held bulk.  For
480
excessive weight, this is probably just a connector-specific check
481
and message on failure, so there might not be much we can do in the
482
library other than make sure the framework is in place.
483
484
---------
485
486
Weapons (attack with)
487
488
---------
489
490
flammability as a mix-in (for paper, wood, and the like)
491
492
---------
493
494
Liquids and bottles
495
496
---------
497
498
Drinkables (special kind of liquid)
499
500
---------
501
502
Probably need a variation of objHeld for liquids that lets us specify
503
that we need to be holding the container of the liquid (for 'pour',
504
for example).  containerHeld?  Or, we could do like we do with keys
505
on keyrings, and consider a liquid within a container being held to
506
be itself held.
507
508
---------
509
510
If we have a bucket or some other container filled with liquid, and
511
we try to put another item into the bucket, we should run a special
512
check for wetting the item.  The default should probably just be to
513
say "you don't want to get that wet" and refuse the command.
514
Similarly, "fill bucket" when the bucket contains non-liquid objects
515
should run the same checks.
516
517
---------
518
519
Burning and liquids: wetting a burning item with a non-flammable
520
liquid should extinguish the flame.
521
522
---------
523
524
Burning and liquids: provide a flammable liquid class.  This should
525
consume the liquid at a particular rate while burning.  The basic
526
flammable fuel consumption mechanism should be used here if possible.
527
528
---------
529
530
Provide an extensible "chemistry" framework for combining different
531
kinds of liquids.
532
533
Perhaps we could define an object to represent the operation of
534
combining each pair of liquid classes - this class doesn't represent
535
the mixture, but rather the operation of mixing.  So, for example, we
536
define an object for the operation of mixing water and liquid
537
nitrogen.
538
539
Each of mixing object must define a method that is called when its
540
pair of liquids are mixed; this method encapsulates the action of
541
mixing the liquids.  Use a global lookup table of these objects,
542
keyed by liquid class pairs; when we want to mix two liquids, we look
543
up the pair of liquid classes to be mixed and find the mixer object,
544
then call its mixer method. 
545
546
---------
547
548
Putting a container with liquid into another container in inventory
549
should have some conditions attached.  First, an openable liquid
550
container should be closed whenever moving it into a sub-container
551
(so a bottle of water should be closed before putting it in your
552
backpack) to avoid spilling.  Second, a container that can't be
553
closed should probably not be allowed to be moved to a sub-container.
554
Third, taking or otherwise moving any item should probably be
555
disallowed if the item contains an open container of liquid.
556
557
---------
558
559
Pouring a liquid onto the floor, into a container that isn't set up
560
as a container for liquids, onto a surface, or onto an arbitrary
561
object should all do something reasonable.  It's unclear what to do
562
in general; the easiest thing would be for the liquid evaporate
563
immediately, but that's not all that realistic.  Pouring liquid onto
564
an arbitrary object should probably call the object's
565
notify-getting-wet method, just as though the object were in a
566
container being filled (although we might want to differentiate
567
between submerging and dousing, maybe just via a flag to the
568
notify-getting-wet method), but then something needs to happen to the
569
liquid, even if the thing that happens is simply evaporation.
570
571
---------
572
573
Leaky containers: when a leaky container has liquid added, it should
574
set up a daemon to cause it to leak slowly.  The liquid leaking out
575
should do whatever liquid does when poured into the leaky object's
576
enclosing location.
577
578
---------
579
580
Absorbent materials: these should retain a quantity of liquid as
581
though they were a liquid container, allowing the absorbed liquid to
582
be recovered by squeezing the object.
583
584
---------
585
586
Ropes, to the extent they can be generalized
587
588
---------
589
590
In two-object actions (including topic and literal actions), when
591
both objects are missing, we might want to consider some alternative
592
way to specify which object we ask for first.  This might vary
593
by language, so it might be better to have an action property that
594
specifies which goes first when both are missing.  Or maybe this is
595
the same as resolution order, or opposite of the resolution order,
596
or something.
597
598
---------
599
600
OBJECTS command - list all portable objects that have been seen, and
601
the last location where they were seen
602
603
---------
604
605
It seems like it should be possible to talk to an actor in situations
606
when the actor is audible only, such as in the dark.  But how do we
607
initiate contact if we don't see the actor?
608
609
1 - broadcast a greeting:  
610
611
>hello
612
Bob says, "Is that you?  I can't see anything."
613
614
2 - try talking to a specific actor:  
615
616
>bob, hello
617
618
This doesn't seem very good because we need to have a way of knowing
619
Bob is present in order to talk to him.
620
621
3 - the actor hears you come in and says he's present:
622
623
>n
624
In the Dark
625
It's pitch black.
626
627
In the darkness, you hear Bob.  "Is that you?" he asks.
628
629
---------
630
631
Add new syntax:
632
633
  x.delegated y.prop(args)
634
635
This syntax explicitly targets 'y' with self as 'x'.  This differs from
636
the regular 'delegated y.prop()' in that the latter can only set 'self'
637
in the delgatee to 'self' in the delegating method.
638
639
Or, perhaps we could take this one step further, by allowing the
640
target object, self, *and* defining object to be independently specified.
641
Something like
642
643
  x.delegated y.inherited z.prop(args)
644
645
646
This would set self to x, target object to y, and defining object to
647
z, then try to find the method in z.  If the method doesn't exist in
648
z, we should probably throw an error rather than try to inherit from
649
there, since this is so fully specified already.
650
651
We would need a new opcode for each case.  The first would require an
652
opcode with the new self, the target object, and the target property
653
as operands; the second would require those operands plus another for
654
the defining object.  We could have two variations of each opcode
655
(one with a fixed property ID and the other with a property pointer
656
operand from the stack), or we could presume that the operands would
657
be rarely used and define only the property pointer version (it would
658
be less efficient for cases with a static property ID, but if the
659
opcode is rarely used, this extra cost shouldn't be important).
660
661
---------
662
663
Add a Set intrinsic class?  (For unordered lists, optimized for inclusion
664
testing: essentially a LookupTable with only the keys.)
665
666
---------
667
668
Soft linking:
669
670
   local x = ifdef(obj);  // if obj is linked in, return obj, else nil
671
672
   replace ifdef obj ...  // same as a new object def if obj isn't linked in
673
674
   modify ifdef obj ...   // ignored if obj isn't linked in
675
676
---------
677
678
List methods: add compare funcs to more methods:
679
   - intersect
680
   - getUnique
681
   - appendUnique
682
683
likewise:
684
   - Array.getUnique
685
   - Array.appendUnique
686
   - Vector.getUnique
687
   - Vector.appendUnique
688
689
---------
690
691
Compiler: equivalent property list syntax: 
692
693
  a, b = foo
694
  c, d(x) { bar }
695
696
---------
697
698
Add items that are by themselves ambiguous?  This might be interesting
699
for things like PO Boxes:
700
701
>look in box
702
Which box do you mean, the cardboard box, or a mail box?
703
704
>mail box
705
Which mail box do you mean?  They're numbered from 23000 to 23999.
706
707
>23001
708
Box 23001 seems to be locked.
709
710
This could be accomplished with an isAmbiguous flag in the object,
711
which would be similar in effect to isEquivalent.  Whenever the object
712
shows up in a list with multiple objects, we use an indefinite article
713
with it, as though it were one of a bunch of equivalent items.  When
714
the object shows up by itself, we ask a single-object disambig
715
question, perhaps by calling a method on the object itself -
716
disambigPrompt?
717
718
Ultimately, matchName() and matchNameDisambig() would be responsible
719
for coming up with a specific object based on the noun phrase.
720
721
---------
722
723
repeated messages: gather up and group defaults?
724
725
---------
726
727
Sound defaults.  Add a background sound resource property to each
728
object.  On each turn, the library scans for all objects in hearing
729
range and plays the associated background sound for each one.  Could
730
have near/far/obscured versions, or maybe simply adjust the volume,
731
or whatever.
732
733
---------
734
735
Graphics defaults.  Add a graphic resource property to each room and
736
item.  On "look" and "examine", display the associated graphic as
737
part of the default room/item description.  It would be especially
738
nice to have a choice of presentation styles, maybe even including a
739
Legend-style split-screen interface (but that might be more
740
appropriate as an add-on; even so, it would be good to keep it in
741
mind so that the necessary hooks are there for creating a
742
Legend-style presentation add-on).
743
744
---------
745
746
Add a music soundtrack scheme that simplifies management of background
747
music.
748
749
---------
750
751
Look into formally structuring things into try/check method pairs
752
(checkHolding/tryHolding, etc), to make precondition implementation
753
more consistent and clear.  This would apply most to the
754
preconditions.
755
756
---------
757
758
Krister Fundin <fundin@yahoo.com> proposes: The list of end-of-game
759
options currently specified as the 'extra' parameter to the
760
finishGame() and finishGameMsg() functions could instead be bundled up
761
into a FinishType object, so that the message and extra options could
762
be specified with just one object parameter.  This would make
763
game-ending code more concise and also make it easier to reuse an
764
option list.
765
766
[We'd probably need a new common function that takes a FinishType
767
object as its sole parameter; the existing interface functions would
768
simply create a dynamic FinishType object to encapsulate the
769
parameters and call the new common function.]
770
771
---------
772
773
Krister Fundin <fundin@yahoo.com> proposes allowing a list parameter
774
in the middle of a parameter list, rather than only as the last
775
parameter, as in foo(a, [b], c).  The compiler could generate function
776
prologue code that moves the trailing arguments into locals, then
777
truncates the list created via PUSHPARLST.  It's a little inefficient,
778
since we just throw away the first list and have to move the locals
779
around, but the case is probably sufficiently rare and non-critical
780
that this doesn't much matter.
781
782
---------
783
784
Andreas Sewe <2003-10-01.as.int-fiction@web.de> proposes that
785
'inherited' in templates should NOT implicitly expand to nothing.  As
786
it is, 'inherited' in a template expands to each inherited superclass
787
template, but also expands to nothing.  Andreas suggests that this
788
should be changed to eliminate the empty expansion, AND the empty
789
template should be allowed, so that it's possible to make inheritors
790
explicitly pick up the empty case.  [It's not entirely clear to me
791
that the empty case really needs to be inherited in the first place,
792
but Andreas's point is that it *could* be there to ensure backwards
793
compatibility with the existing template structure, which implicitly
794
does inherit the empty case.]
795
796
---------
797
798
From <2003-10-01.as.int-fiction@web.de>: add a way of naming
799
anonymous functions (which would make the name an oxymoron, so
800
I suppose we'd have to rename them to "in-line" functions
801
or similar).  Something like this:
802
803
 local f = new function factorial(n) { return n > 1 ? n*factorial(n-1) : 1; };
804
805
---------
806
807
From Krister Fundin <fundin@yahoo.com>: add
808
TadsObject.forEachSuperclass(); takes a callback function pointer as
809
its argument.  This would iterate through all of the direct and
810
indirect superclasses of an object.  (This is readily implementable in
811
byte code, but the VM might have the class hierarchy cached, so it
812
could iterate through them more efficiently than byte code could.)
813
814
---------
815
816
From Robey Holderith <robey@flaminglunchbox.net>: add a new
817
Python-style string notation: use three single quotes in a row as
818
an alternative single-quoted string delimiter.  For example:
819
820
   '''Sorry, she's not here right now.'''
821
822
would be treated as equivalent to
823
824
   'Sorry, she\'s not here right now.'
825
826
Many people find the Python notation more readable than the present
827
backslash notation.  The backslash notation would be retained as well;
828
this would just be a new, optional variation.  (There's some
829
compatibility risk, but it's probably negligible - it's hard to come
830
up with any example of where a tripled quote like this would be useful
831
in the present notation.)
832
833
---------
834
835
From steve breslin <steve.breslin@gmail.com>: Add auto-completion
836
popup lists and parameter-list tooltips to the editor, a la
837
"intellisense" in msft dev env's.  Scintilla has native support for
838
both of these (the "autocomplete" and "call tips" features), so
839
there'd be no UI work; it's just a matter of monitoring keystrokes,
840
generating the popup/tip data, and making the appropriate SCI_xxx
841
calls to activate the features.
842
843
The main difficulty is that TADS is not a statically typed language,
844
so it's not possible in principal to generate the popup data that you
845
can in a language like C++, where you can determine the type of any
846
expression at compile time (and thus at editing time).  You could find
847
the popup information only when referring directly to an object by
848
name.  I'm not sure if the result would be useful enough to justify
849
the work.
850
851
The other complication is that I don't think the compiler currently
852
provides any sort of convenient packaging for the sort of information
853
you'd need to generate the popups; it would probably require some
854
compiler work to generate a little database giving the method list for
855
each object.  This wouldn't be a ton of work but wouldn't be free.
856
857
---------
858
859
From Knight Errant <sigmundvondanzig@gmail.com>: add a spell-checker
860
to Workbench.  (Could be an on-the-fly spell checker a la Word's
861
squiggly underlines, or could be an explicit separate step.  I think
862
Scintilla has some built-in support for the display part of on-the-fly
863
spell checking, so that would probably be the way to go.  Spell
864
checking would be most useful if it were mode-sensitive, so that, for
865
example, the tads3 mode would only check text within strings, and
866
exclude HTML substrings.  Presumably we could use the style
867
information to do this.)
868
869
---------
870
871
From Eric Eve <eric.eve@hmc.ox.ac.uk>: It would be quite nice if
872
TravelBarrier objects had some easy way to refer to the connector
873
through which they're blocking travel in their explainTravelBarrier()
874
method. One way to do this might be to add a second parameter to
875
TravelBarrier.explainTravelBarrier and then have
876
TravelConnector.checkTravelBarriers() call
877
explainTravelBarrier(traveler, self) instead of
878
explainTravelBarrier(traveler); but this could break a lot of existing
879
code. The slightly messier alternative, which might nevertheless
880
better preserve backward compatibility would be to add a connector
881
property to TravelBarrier and then add cur.connector = self just
882
before cur.explainTravelBarrier(traveler) in the foreach(cur in lst)
883
loop in TravelConnector.checkTravelBarriers().
884
885
---------
886
887
From Eric Eve <eric.eve@hmc.ox.ac.uk>: At present attempting to travel
888
via an AskConnector will always prefer an open door to a closed one
889
(without prompting the player to specify which door s/he wants to go
890
through). This may be fine as default behaviour but sometimes in might
891
be nice to allow the option of always prompting the player to specify
892
which door is meant. (I can see that this might be quite fiddly to
893
achieve, and if it's too fiddly then by all means don't pursue it;
894
it's hardly high priority).
895
896
---------
897
898
From Eric Eve <eric.eve@hmc.ox.ac.uk>: IIRC this came up before, but I
899
can't remember that it was ever pursued. It would be quite nice if
900
ThingMatchTopic could match on a class as well as an object, e.g.:
901
902
ThingMatchTopic.matchTopic(fromActor, obj)
903
{
904
        /*
905
         *   if matchObj is a collection, check each element, otherwise
906
         *   just match the single object
907
         */
908
        if (matchObj.ofKind(Collection))
909
        {
910
            /* try matching each object in the list */
911
            if (matchObj.indexWhich({cur: obj.ofKind(cur)}) != nil)
912
                return matchScore;
913
        }
914
        else
915
        {
916
            /* match the single object */
917
            if (obj.ofKind(matchObj))
918
                return matchScore;
919
        }
920
921
        /* didn't find a match - indicate this by returning a nil score */
922
        return nil;
923
    }
924
925
With corresponding changes to ThingMatchTopic.isMatchPossible().
926
927
So far as I can see this shouldn't break any existing code (if
928
obj==matchObj then obj.ofKind(matchObj)), but would allow for greater
929
flexibility, making it easier to write responses such as:
930
931
+ GiveShowTopic @Food
932
  topicResponse()
933
  {
934
     gDobj.moveInto(nil);
935
     "Bob snatches {the dobj/him} from you and wolfs it down.\b
936
      <q>Thanks,</q> he says, <q>I needed that -- I waa starving!</q>";
937
  }
938
;
939
---------
940
941
From Eric Eve <eric.eve@hmc.ox.ac.uk>: Some time ago Michel sent me
942
some very nice code to add a vocabLikehihood property to VocabObject,
943
which allows authors to nudge the parser to prefering some objects to
944
others when all other distinguishers fail. I've found it pretty useful
945
ever since and I think it would make a nice addition to the standard
946
library if Michel were willing to contribute it.
947