-
Notifications
You must be signed in to change notification settings - Fork 1
/
de_de.t
18026 lines (15955 loc) · 661 KB
/
de_de.t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#charset "latin1"
/*
* Copyright 2000, 2006 Michael J. Roberts. All Rights Reserved.
*. Past-tense extensions written by Michel Nizette, and incorporated by
* permission.
*
* We have attempted to isolate here the parts of the library that are
* language-specific, so that translations to other languages or dialects
* can be created by replacing this module, without changing the rest of
* the library.
*
* In addition to this module, a separate set of US English messages are
* defined in the various msg_xxx.t modules. Those modules define
* messages in English for different stylistic variations. For a given
* game, the author must select one of the message modules - but only
* one, since they all define variations of the same messages. To
* translate the library, a translator must create at least one module
* defining those messages as well; only one message module is required
* per language.
*
* The past-tense system was contributed by Michel Nizette.
*
*. -----
*
* "Watch an immigrant struggling with a second language or a stroke
* patient with a first one, or deconstruct a snatch of baby talk, or try
* to program a computer to understand English, and ordinary speech
* begins to look different."
*
*. Stephen Pinker, "The Language Instinct"
*/
/*
* TADS 3 Library - German (German variant) implementation by Michael Baltes
*
* -- This defines the parts of the TADS 3 library that are specific to the
* -- German language as spoken (and written) in Germany.
*
*/
#include "tads.h"
#include "tok.h"
#include "adv3.h"
#include "de_de.h"
#include <vector.h>
#include <dict.h>
#include <gramprod.h>
#include <strcomp.h>
// -- setup of version info for Library
libraryInfo: object
version = '2.2 - 150930'
;
/* ------------------------------------------------------------------------ */
/*
* Fill in the default language for the GameInfo metadata class.
*/
modify GameInfoModuleID
languageCode = 'de-de'
;
/* ------------------------------------------------------------------------ */
/*
* Simple yes/no confirmation. The caller must display a prompt; we'll
* read a command line response, then return true if it's an affirmative
* response, nil if not.
*/
yesOrNo()
{
/* switch to no-command mode for the interactive input */
"<.commandnone>";
/*
* Read a line of input. Do not allow real-time event processing;
* this type of prompt is used in the middle of a command, so we
* don't want any interruptions. Note that the caller must display
* any desired prompt, and since we don't allow interruptions, we
* won't need to redisplay the prompt, so we pass nil for the prompt
* callback.
*/
local str = inputManager.getInputLine(nil, nil);
/* switch back to mid-command mode */
"<.commandmid>";
/* ##### 'J' instead if 'y' #####
* If they answered with something starting with 'J', it's
* affirmative, otherwise it's negative. In reading the response,
* ignore any leading whitespace.
*/
return rexMatch('<space>*[jJ]', str) != nil;
}
/* ------------------------------------------------------------------------ */
/*
* During start-up, install a case-insensitive truncating comparator in
* the main dictionary.
*/
PreinitObject
execute()
{
/* set up the main dictionary's comparator */
languageGlobals.setStringComparator(
new StringComparator(gameMain.parserTruncLength, nil, [['\u00DF','ss',0,0],['\u00F6','oe',0,0],['\u00E4','ae',0,0],['\u00FC','ue',0,0]]));
}
/*
* Make sure we run BEFORE the main library preinitializer, so that
* we install the comparator in the dictionary before we add the
* vocabulary words to the dictionary. This doesn't make any
* difference in terms of the correctness of the dictionary, since
* the dictionary will automatically rebuild itself whenever we
* install a new comparator, but it makes the preinitialization run
* a tiny bit faster by avoiding that rebuild step.
*/
execAfterMe = [adv3LibPreinit]
;
/* ------------------------------------------------------------------------ */
/*
* Language-specific globals
*/
languageGlobals: object
/*
* Set the StringComparator object for the parser. This sets the
* comparator that's used in the main command parser dictionary.
*/
setStringComparator(sc)
{
/* remember it globally, and set it in the main dictionary */
dictComparator = sc;
cmdDict.setComparator(sc);
}
/*
* The character to use to separate groups of digits in large
* numbers. US English uses commas; most Europeans use periods.
*
* Note that this setting does not affect system-level BigNumber
* formatting, but this information can be passed when calling
* BigNumber formatting routines.
*/
// ##### Changed into period #####
digitGroupSeparator = '.'
/*
* The decimal point to display in floating-point numbers. US
* English uses a period; most Europeans use a comma.
*
* Note that this setting doesn't affect system-level BigNumber
* formatting, but this information can be passed when calling
* BigNumber formatting routines.
*/
// ##### Changed into comma #####
decimalPointCharacter = ','
/* the main dictionary's string comparator */
dictComparator = nil
;
/* ------------------------------------------------------------------------ */
/*
* Language-specific extension of the default gameMain object
* implementation.
*/
modify GameMainDef
/*
* Option setting: the parser's truncation length for player input.
* As a convenience to the player, we can allow the player to
* truncate long words, entering only the first, say, 6 characters.
* For example, rather than typing "x flashlight", we could allow the
* player to simply type "x flashl" - truncating "flashlight" to six
* letters.
*
* We use a default truncation length of 6, but games can change this
* by overriding this property in gameMain. We use a default of 6
* mostly because that's what the old Infocom games did - many
* long-time IF players are accustomed to six-letter truncation from
* those games. Shorter lengths are superficially more convenient
* for the player, obviously, but there's a trade-off, which is that
* shorter truncation lengths create more potential for ambiguity.
* For some games, a longer length might actually be better for the
* player, because it would reduce spurious ambiguity due to the
* parser matching short input against long vocabulary words.
*
* If you don't want to allow the player to truncate long words at
* all, set this to nil. This will require the player to type every
* word in its entirety.
*
* Note that changing this property dynamicaly will have no effect.
* The library only looks at it once, during library initialization
* at the very start of the game. If you want to change the
* truncation length dynamically, you must instead create a new
* StringComparator object with the new truncation setting, and call
* languageGlobals.setStringComparator() to select the new object.
*/
// #################################################
// ## modified (standard = 6) because of rather ##
// ## "long" words like 'Schlüsselbund' in German ##
// #################################################
parserTruncLength = 16
/*
* Option: are we currently using a past tense narrative? By
* default, we aren't.
*
* This property can be reset at any time during the game in order to
* switch between the past and present tenses. The macro
* setPastTense can be used for this purpose: it just provides a
* shorthand for setting gameMain.usePastTense directly.
*
* Authors who want their game to start in the past tense can achieve
* this by overriding this property on their gameMain object and
* giving it a value of true.
*/
usePastTense = nil
;
/* ------------------------------------------------------------------------ */
/*
* Language-specific modifications for ThingState.
*/
modify ThingState
/*
* Our state-specific tokens. This is a list of vocabulary words
* that are state-specific: that is, if a word is in this list, the
* word can ONLY refer to this object if the object is in a state
* with that word in its list.
*
* The idea is that you set up the object's "static" vocabulary with
* the *complete* list of words for all of its possible states. For
* example:
*
*. + Matchstick 'lit unlit match';
*
* Then, you define the states: in the "lit" state, the word 'lit' is
* in the stateTokens list; in the "unlit" state, the word 'unlit' is
* in the list. By putting the words in the state lists, you
* "reserve" the words to their respective states. When the player
* enters a command, the parser will limit object matches so that the
* reserved state-specific words can only refer to objects in the
* corresponding states. Hence, if the player refers to a "lit
* match", the word 'lit' will only match an object in the "lit"
* state, because 'lit' is a reserved state-specific word associated
* with the "lit" state.
*
* You can re-use a word in multiple states. For example, you could
* have a "red painted" state and a "blue painted" state, along with
* an "unpainted" state.
*/
stateTokens = []
/*
* Match the name of an object in this state. We'll check the token
* list for any words that apply only to *other* states the object
* can assume; if we find any, we'll reject the match, since the
* phrase must be referring to an object in a different state.
*/
matchName(obj, origTokens, adjustedTokens, states)
{
/* scan each word in our adjusted token list */
for (local i = 1, local len = adjustedTokens.length() ;
i <= len ; i += 2)
{
/* get the current token */
local cur = adjustedTokens[i];
/*
* If this token is in our own state-specific token list,
* it's acceptable as a match to this object. (It doesn't
* matter whether or not it's in any other state's token list
* if it's in our own, because its presence in our own makes
* it an acceptable matching word when we're in this state.)
*/
if (stateTokens.indexWhich({t: t == cur}) != nil)
continue;
/*
* It's not in our own state-specific token list. Check to
* see if the word appears in ANOTHER state's token list: if
* it does, then this word CAN'T match an object in this
* state, because the token is special to that other state
* and thus can't refer to an object in a state without the
* token.
*/
if (states.indexWhich(
{s: s.stateTokens.indexOf(cur) != nil}) != nil)
return nil;
}
/* we didn't find any objection, so we can match this phrase */
return obj;
}
/*
* Check a token list for any tokens matching any of our
* state-specific words. Returns true if we find any such words,
* nil if not.
*
* 'toks' is the *adjusted* token list used in matchName().
*/
findStateToken(toks)
{
/*
* Scan the token list for a match to any of our state-specific
* words. Since we're using the adjusted token list, every
* other entry is a part of speech, so work through the list in
* pairs.
*/
for (local i = 1, local len = toks.length() ; i <= len ; i += 2)
{
/*
* if this token matches any of our state tokens, indicate
* that we found a match
*/
if (stateTokens.indexWhich({x: x == toks[i]}) != nil)
return true;
}
/* we didn't find a match */
return nil;
}
/* get our name */
listName(lst) { return listName_; }
/*
* our list name setting - we define this so that we can be easily
* initialized with a template (we can't initialize listName()
* directly in this manner because it's a method, but we define the
* listName() method to simply return this property value, which we
* can initialize with a template)
*/
listName_ = nil
;
/* ------------------------------------------------------------------------ */
/*
* Language-specific modifications for VocabObject.
*/
modify VocabObject
/*
* The vocabulary initializer string for the object - this string
* can be initialized (most conveniently via a template) to a string
* of this format:
*
* 'adj adj adj noun/noun/noun*plural plural plural'
*
* The noun part of the string can be a hyphen, '-', in which case
* it means that the string doesn't specify a noun or plural at all.
* This can be useful when nouns and plurals are all inherited from
* base classes, and only adjectives are to be specified. (In fact,
* any word that consists of a single hyphen will be ignored, but
* this is generally only useful for the adjective-only case.)
*
* During preinitialization, we'll parse this string and generate
* dictionary entries and individual vocabulary properties for the
* parts of speech we find.
*
* Note that the format described above is specific to the English
* version of the library. Non-English versions will probably want
* to use different formats to conveniently encode appropriate
* language-specific information in the initializer string. See the
* comments for initializeVocabWith() for more details.
*
* You can use the special wildcard # to match any numeric
* adjective. This only works as a wildcard when it stands alone,
* so a string like "7#" is matched as that literal string, not as a
* wildcard. If you want to use a pound sign as a literal
* adjective, just put it in double quotes.
*
* You can use the special wildcard "\u0001" (include the double
* quotes within the string) to match any literal adjective. This
* is the literal adjective equivalent of the pound sign. We use
* this funny character value because it is unlikely ever to be
* interesting in user input.
*
* If you want to match any string for a noun and/or adjective, you
* can't do it with this property. Instead, just add the property
* value noun='*' to the object.
*/
vocabWords = ''
/*
* On dynamic construction, initialize our vocabulary words and add
* them to the dictionary.
*/
construct()
{
/* initialize our vocabulary words from vocabWords */
initializeVocab();
/* add our vocabulary words to the dictionary */
addToDictionary(&noun);
addToDictionary(&adjective);
addToDictionary(&plural);
addToDictionary(&adjApostS);
addToDictionary(&literalAdjective);
addToDictionary(&maleSyn); // ##### new dictionary property for changing gender #####
addToDictionary(&femaleSyn); // ##### new dictionary property for changing gender #####
addToDictionary(&neuterSyn); // ##### new dictionary property for changing gender #####
addToDictionary(&pluralSyn); // ##### new dictionary property for changing gender #####
addToDictionary(&irregularNWord); // ##### new dictionary property for keinen(txt) #####
}
/* add the words from a dictionary property to the global dictionary */
addToDictionary(prop)
{
/* if we have any words defined, add them to the dictionary */
if (self.(prop) != nil)
cmdDict.addWord(self, self.(prop), prop);
}
/* initialize the vocabulary from vocabWords */
initializeVocab()
{
/* inherit vocabulary from this class and its superclasses */
inheritVocab(self, new Vector(10));
}
/*
* Inherit vocabulary from this class and its superclasses, adding
* the words to the given target object. 'target' is the object to
* which we add our vocabulary words, and 'done' is a vector of
* classes that have been visited so far.
*
* Since a class can be inherited more than once in an inheritance
* tree (for example, a class can have multiple superclasses, each
* of which have a common base class), we keep a vector of all of
* the classes we've visited. If we're already in the vector, we'll
* skip adding vocabulary for this class or its superclasses, since
* we must have already traversed this branch of the tree from
* another subclass.
*/
inheritVocab(target, done)
{
/*
* if we're in the list of classes handled already, don't bother
* visiting me again
*/
if (done.indexOf(self) != nil)
return;
/* add myself to the list of classes handled already */
done.append(self);
/*
* add words from our own vocabWords to the target object (but
* only if it's our own - not if it's only inherited, as we'll
* pick up the inherited ones explicitly in a bit)
*/
if (propDefined(&vocabWords, PropDefDirectly))
target.initializeVocabWith(vocabWords);
/* add vocabulary from each of our superclasses */
foreach (local sc in getSuperclassList())
sc.inheritVocab(target, done);
}
/*
* Initialize our vocabulary from the given string. This parses the
* given vocabulary initializer string and adds the words defined in
* the string to the dictionary.
*
* Note that this parsing is intentionally located in the
* English-specific part of the library, because it is expected that
* other languages will want to define their own vocabulary
* initialization string formats. For example, a language with
* gendered nouns might want to use gendered articles in the
* initializer string as an author-friendly way of defining noun
* gender; languages with inflected (declined) nouns and/or
* adjectives might want to encode inflected forms in the
* initializer. Non-English language implementations are free to
* completely redefine the format - there's no need to follow the
* conventions of the English format in other languages where
* different formats would be more convenient.
*/
initializeVocabWith(str)
{
local sectPart;
local modList = [];
/* start off in the adjective section */
sectPart = &adjective;
/* scan the string until we run out of text */
while (str != '')
{
local len;
local cur;
local cut;
/*
* if it starts with a quote, find the close quote;
* otherwise, find the end of the current token by seeking
* the next delimiter
*/
if (str.startsWith('"'))
{
/* find the close quote */
len = str.find('"', 2);
}
else
{
/* no quotes - find the next delimiter */
len = rexMatch('<^space|star|/>*', str);
}
/* if there's no match, use the whole rest of the string */
if (len == nil)
len = str.length();
/* if there's anything before the delimiter, extract it */
if (len != 0)
{
/* extract the part up to but not including the delimiter */
cur = str.substr(1, len);
/*
* if we're in the adjectives, and either this is the
* last token or the next delimiter is not a space, this
* is implicitly a noun
*/
if (sectPart == &adjective
&& (len == str.length()
|| str.substr(len + 1, 1) != ' '))
{
/* move to the noun section */
sectPart = &noun;
}
/*
* if the word isn't a single hyphen (in which case it's
* a null word placeholder, not an actual vocabulary
* word), add it to our own appropriate part-of-speech
* property and to the dictionary
*/
if (cur != '-')
{
/*
* by default, use the part of speech of the current
* string section as the part of speech for this
* word
*/
local wordPart = sectPart;
/*
* Check for parentheses, which indicate that the
* token is "weak." This doesn't affect anything
* about the token or its part of speech except that
* we must include the token in our list of weak
* tokens.
*/
if (cur.startsWith('(') && cur.endsWith(')'))
{
/* it's a weak token - remove the parens */
cur = cur.substr(2, cur.length() - 2);
/*
* if we don't have a weak token list yet,
* create the list
*/
if (weakTokens == nil)
weakTokens = [];
/* add the token to the weak list */
weakTokens += cur;
}
// ##################################################
// ## new dictionary property &irregularNWord ##
// ## for synonyms with a -n accusative ending, as ##
// ## in "affe[-n]" for keinen(txt) and viele(txt) ##
// ## "Du siehst hier keinen Affen. " ##
// ##################################################
if (cur.endsWith('[-n]'))
{
/* change the part of speech to 'irregularNWord' */
wordPart = &irregularNWord;
/* remove the '[-n]' suffix from the string */
cur = cur.substr(1, cur.length() - 4);
// ##### remove possible changing genders before adding it #####
if (cur.endsWith('[m]') || cur.endsWith('[f]') || cur.endsWith('[n]') ||cur.endsWith('[p]'))
cut = cur.substr(1, cur.length() - 3);
else
cut = cur;
/* add it to the dictionary */
cmdDict.addWord(self, cut, wordPart);
/* move to the noun section */
wordPart = sectPart;
}
/*
* Check for special formats: quoted strings,
* apostrophe-S words. These formats are mutually
* exclusive.
*/
if (cur.startsWith('"'))
{
/*
* It's a quoted string, so it's a literal
* adjective.
*/
/* remove the quote(s) */
if (cur.endsWith('"'))
cur = cur.substr(2, cur.length() - 2);
else
cur = cur.substr(2);
/* change the part of speech to 'literal adjective' */
wordPart = &literalAdjective;
}
else if (cur.endsWith('\'s'))
{
/*
* It's an apostrophe-s word. Remove the "'s"
* suffix and add the root word using adjApostS
* as the part of speech. The grammar rules are
* defined to allow this part of speech to be
* used exclusively with "'s" suffixes in input.
* Since the tokenizer always pulls the "'s"
* suffix off of a word in the input, we have to
* store any vocabulary words with "'s" suffixes
* the same way, with the "'s" suffixes removed.
*/
/* change the part of speech to adjApostS */
wordPart = &adjApostS;
/* remove the "'s" suffix from the string */
cur = cur.substr(1, cur.length() - 2);
}
// -- German changing gender -- if a string endswith [m] ->
// cut it off and add it to maleSyn
else if (cur.endsWith('[m]'))
{
/*
* It's a maleSyn, a synonym for an object which
* has another gender than the object itself
*/
/* change the part of speech to 'maleSyn' */
wordPart = &maleSyn;
/* remove the '[m]' suffix from the string */
cur = cur.substr(1, cur.length() - 3);
}
// -- German changing gender -- if a string endswith [f] ->
// cut it off and add it to femaleSyn
else if (cur.endsWith('[f]'))
{
/*
* It's a femaleSyn, a synonym for an object which
* has another gender than the object itself
*/
/* change the part of speech to 'femaleSyn' */
wordPart = &femaleSyn;
/* remove the '[f]' suffix from the string */
cur = cur.substr(1, cur.length() - 3);
}
// -- German changing gender -- if a string endswith [n] ->
// cut it off and add it to neuterSyn
else if (cur.endsWith('[n]'))
{
/*
* It's a neuterSyn, a synonym for an object which
* has another gender than the object itself
*/
/* change the part of speech to 'neuterSyn' */
wordPart = &neuterSyn;
/* remove the '[n]' suffix from the string */
cur = cur.substr(1, cur.length() - 3);
}
// -- German changing gender -- if a string endswith [p] ->
// cut it off and add it to pluralSyn
else if (cur.endsWith('[p]'))
{
/*
* It's a pluralSyn, a synonym for an object which
* has another gender than the object itself
*/
/* change the part of speech to 'pluralSyn' */
wordPart = &pluralSyn;
/* remove the '[p]' suffix from the string */
cur = cur.substr(1, cur.length() - 3);
}
// #############################################
// ## we put all vocabWords in ...Syn because ##
// ## we need this for correct disambiguation ##
// #############################################
if (wordPart == &noun) {
if (self.isHim)
wordPart = &maleSyn;
else if (self.isHer)
wordPart = &femaleSyn;
else if (self.isPlural)
wordPart = &pluralSyn;
else
wordPart = &neuterSyn;
}
/* add the word to our own list for this part of speech */
if (self.(wordPart) == nil)
self.(wordPart) = [cur];
else
self.(wordPart) += cur;
/* add it to the dictionary */
cmdDict.addWord(self, cur, wordPart);
if (cur.endsWith('.'))
{
local abbr;
/*
* It ends with a period, so this is an
* abbreviated word. Enter the abbreviation
* both with and without the period. The normal
* handling will enter it with the period, so we
* only need to enter it specifically without.
*/
abbr = cur.substr(1, cur.length() - 1);
self.(wordPart) += abbr;
cmdDict.addWord(self, abbr, wordPart);
}
/* note that we added to this list */
if (modList.indexOf(wordPart) == nil)
modList += wordPart;
}
}
/* if we have a delimiter, see what we have */
if (len + 1 < str.length())
{
/* check the delimiter */
switch(str.substr(len + 1, 1))
{
case ' ':
/* stick with the current part */
break;
case '*':
/* start plurals */
sectPart = &plural;
break;
case '/':
/* start alternative nouns */
sectPart = &noun;
break;
}
/* remove the part up to and including the delimiter */
str = str.substr(len + 2);
/* skip any additional spaces following the delimiter */
if ((len = rexMatch('<space>+', str)) != nil)
str = str.substr(len + 1);
}
else
{
/* we've exhausted the string - we're done */
break;
}
}
/* uniquify each word list we updated */
foreach (local p in modList)
self.(p) = self.(p).getUnique();
}
;
/* ------------------------------------------------------------------------ */
/*
* Language-specific modifications for Thing. This class contains the
* methods and properties of Thing that need to be replaced when the
* library is translated to another language.
*
* The properties and methods defined here should generally never be used
* by language-independent library code, because everything defined here
* is specific to English. Translators are thus free to change the
* entire scheme defined here. For example, the notions of number and
* gender are confined to the English part of the library; other language
* implementations can completely replace these attributes, so they're
* not constrained to emulate their own number and gender systems with
* the English system.
*/
modify Thing
/*
* Flag that this object's name is rendered as a plural (this
* applies to both a singular noun with plural usage, such as
* "pants" or "scissors," and an object used in the world model to
* represent a collection of real-world objects, such as "shrubs").
*/
isPlural = nil
/*
* Flag that this is object's name is a "mass noun" - that is, a
* noun denoting a continuous (effectively infinitely divisible)
* substance or material, such as water, wood, or popcorn; and
* certain abstract concepts, such as knowledge or beauty. Mass
* nouns are never rendered in the plural, and use different
* determiners than ordinary ("count") nouns: "some popcorn" vs "a
* kernel", for example.
*/
isMassNoun = nil
/*
* Flags indicating that the object should be referred to with
* gendered pronouns (such as 'he' or 'she' rather than 'it').
*
* Note that these flags aren't mutually exclusive, so it's legal
* for the object to have both masculine and feminine usage. This
* can be useful when creating collective objects that represent
* more than one individual, for example.
*/
isHim = nil // ##### for masculine nouns #####
isHer = nil // ##### for feminine nouns #####
isYours = nil // ##### new property for yours, this adds a "dein/mein/sein" before derName, etc. #####
// ##### but does not(!) set the owner property, do this by owner = ... #####
// ##### In the original library this is obsolete, as they use name = 'your cat' #####
isDefinite = nil // ##### for thing that have only the definite #####
// ##### article like "Der junge Werther" #####
/*
* Flag indicating that the object can be referred to with a neuter
* pronoun ('it'). By default, this is true if the object has
* neither masculine nor feminine gender, but it can be overridden
* so that an object has both gendered and ungendered usage. This
* can be useful for collective objects, as well as for cases where
* gendered usage varies by speaker or situation, such as animals.
*/
isIt // ##### for neuter nouns #####
{
/* by default, we're an 'it' if we're not a 'him' or a 'her' or a pluralword */
return !(isHim || isHer || isPlural);
}
/*
* Test to see if we can match the pronouns 'him', 'her', 'it', and
* 'them'. By default, these simply test the corresponding isXxx
* flags (except 'canMatchThem', which tests 'isPlural' to see if the
* name has plural usage).
*/
canMatchHim = (isHim)
canMatchHer = (isHer)
canMatchIt = (isIt)
canMatchThem = (isPlural)
// ####################################################################
// ## special flag which is used to check if the player refers to ##
// ## an synonym word, which has another gender as the object itself ##
// ## e.g: 'die Jacke', but 'der Anorak' ##
// ####################################################################
maleSynFlag = nil
femaleSynFlag = nil
neuterSynFlag = nil
pluralSynFlag = nil
/* can we match the given PronounXxx pronoun type specifier? */
canMatchPronounType(typ)
{
/* check the type, and return the appropriate indicator property */
switch (typ)
{
case PronounHim:
return canMatchHim;
case PronounHer:
return canMatchHer;
case PronounIt:
return canMatchIt;
case PronounThem:
return canMatchThem;
default:
return nil;
}
}
/*
* The grammatical cardinality of this item when it appears in a
* list. This is used to ensure verb agreement when mentioning the
* item in a list of items. ("Cardinality" is a fancy word for "how
* many items does this look like").
*
* English only distinguishes two degrees of cardinality in its
* grammar: one, or many. That is, when constructing a sentence, the
* only thing the grammar cares about is whether an object is
* singular or plural: IT IS on the table, THEY ARE on the table.
* Since English only distinguishes these two degrees, two is the
* same as a hundred is the same as a million for grammatical
* purposes, so we'll consider our cardinality to be 2 if we're
* plural, 1 otherwise.
*
* Some languages don't express cardinality at all in their grammar,
* and others distinguish cardinality in greater detail than just
* singular-vs-plural, which is why this method has to be in the
* language-specific part of the library.
*/
listCardinality(lister) { return isPlural ? 2 : 1; }
/*
* Proper name flag. This indicates that the 'name' property is the
* name of a person or place. We consider proper names to be fully
* qualified, so we don't add articles for variations on the name
* such as 'theName'.
*/
isProperName = nil
/*
* Qualified name flag. This indicates that the object name, as
* given by the 'name' property, is already fully qualified, so
* doesn't need qualification by an article like "the" or "a" when
* it appears in a sentence. By default, a name is considered
* qualified if it's a proper name, but this can be overridden to
* mark a non-proper name as qualified when needed.
*/
isQualifiedName = (isProperName)
/*
* The name of the object - this is a string giving the object's
* short description, for constructing sentences that refer to the
* object by name. Each instance should override this to define the
* name of the object. This string should not contain any articles;
* we use this string as the root to generate various forms of the
* object's name for use in different places in sentences.
*/
name = ''
/*
* The name of the object, for the purposes of disambiguation
* prompts. This should almost always be the object's ordinary
* name, so we return self.name by default.
*
* In rare cases, it might be desirable to override this. In
* particular, if a game has two objects that are NOT defined as
* basic equivalents of one another (which means that the parser
* will always ask for disambiguation when the two are ambiguous
* with one another), but the two nonetheless have identical 'name'
* properties, this property should be overridden for one or both
* objects to give them different names. This will ensure that we
* avoid asking questions of the form "which do you mean, the coin,
* or the coin?". In most cases, non-equivalent objects will have
* distinct 'name' properties to begin with, so this is not usually
* an issue.
*
* When overriding this method, take care to override
* theDisambigName, aDisambigName, countDisambigName, and/or
* pluralDisambigName as needed. Those routines must be overridden
* only when the default algorithms for determining articles and
* plurals fail to work properly for the disambigName (for example,
* the indefinite article algorithm fails with silent-h words like
* "hour", so if disambigName is "hour", aDisambigName must be
* overridden). In most cases, the automatic algorithms will
* produce acceptable results, so the default implementations of
* these other routines can be used without customization.
*/
disambigName = (name)
/*
* The "equivalence key" is the value we use to group equivalent
* objects. Note that we can only treat objects as equivalent when
* they're explicitly marked with isEquivalent=true, so the
* equivalence key is irrelevant for objects not so marked.
*
* Since the main point of equivalence is to allow creation of groups
* of like-named objects that are interchangeable in listings and in
* command input, we use the basic disambiguation name as the
* equivalence key.
*/
equivalenceKey = (disambigName)