OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / autopick / autopick-editor-command.cpp
1 /*!
2  * @brief 自動拾いエディタ画面でキーを押した時の挙動一式
3  * @date 2020/04/26
4  * @author Hourier
5  * @todo これ単体で700行を超えているので要分割
6  */
7
8 #include "autopick/autopick-editor-command.h"
9 #include "autopick/autopick-commands-table.h"
10 #include "autopick/autopick-dirty-flags.h"
11 #include "autopick/autopick-drawer.h"
12 #include "autopick/autopick-editor-util.h"
13 #include "autopick/autopick-entry.h"
14 #include "autopick/autopick-finder.h"
15 #include "autopick/autopick-flags-table.h"
16 #include "autopick/autopick-inserter-killer.h"
17 #include "autopick/autopick-methods-table.h"
18 #include "autopick/autopick-reader-writer.h"
19 #include "autopick/autopick-util.h"
20 #include "core/asking-player.h"
21 #include "core/show-file.h"
22 #include "game-option/input-options.h"
23 #include "game-option/keymap-directory-getter.h"
24 #include "player-info/class-info.h"
25 #include "player-info/race-info.h"
26 #include "system/player-type-definition.h"
27 #include "term/term-color-types.h"
28 #include "term/z-form.h"
29
30 /*!
31  * @brief
32  * @param player_ptr プレイヤーへの参照ポインタ
33  * @param tb 自動拾いの構文
34  * @param com_id エディタ内で打ったコマンド
35  * @return
36  * @details Execute a single editor command
37  */
38 ape_quittance do_editor_command(PlayerType *player_ptr, text_body_type *tb, int com_id)
39 {
40     switch (com_id) {
41     case EC_QUIT: {
42         if (tb->changed) {
43             if (!get_check(_("全ての変更を破棄してから終了します。よろしいですか? ", "Discard all changes and quit. Are you sure? "))) {
44                 break;
45             }
46         }
47
48         return APE_QUIT_WITHOUT_SAVE;
49     }
50     case EC_SAVEQUIT:
51         return APE_QUIT_AND_SAVE;
52     case EC_REVERT: {
53         if (!get_check(_("全ての変更を破棄して元の状態に戻します。よろしいですか? ", "Discard all changes and revert to original file. Are you sure? "))) {
54             break;
55         }
56
57         free_text_lines(tb->lines_list);
58         tb->lines_list = read_pickpref_text_lines(player_ptr, &tb->filename_mode);
59         tb->dirty_flags |= DIRTY_ALL | DIRTY_MODE | DIRTY_EXPRESSION;
60         tb->cx = tb->cy = 0;
61         tb->mark = 0;
62         tb->changed = false;
63         break;
64     }
65     case EC_HELP: {
66         (void)show_file(player_ptr, true, _("jeditor.txt", "editor.txt"), 0, 0);
67         tb->dirty_flags |= DIRTY_SCREEN;
68         break;
69     }
70     case EC_RETURN: {
71         if (tb->mark) {
72             tb->mark = 0;
73             tb->dirty_flags |= DIRTY_ALL;
74         }
75
76         if (!insert_return_code(tb)) {
77             break;
78         }
79         tb->cy++;
80         tb->cx = 0;
81         tb->dirty_flags |= DIRTY_ALL;
82         break;
83     }
84     case EC_LEFT: {
85         if (0 < tb->cx) {
86             int len;
87 #ifdef JP
88             int i;
89 #endif
90             tb->cx--;
91             len = strlen(tb->lines_list[tb->cy]);
92             if (len < tb->cx) {
93                 tb->cx = len;
94             }
95 #ifdef JP
96             for (i = 0; tb->lines_list[tb->cy][i]; i++) {
97                 if (iskanji(tb->lines_list[tb->cy][i])) {
98                     i++;
99                     if (i == tb->cx) {
100                         tb->cx--;
101                         break;
102                     }
103                 }
104             }
105 #endif
106         } else if (tb->cy > 0) {
107             tb->cy--;
108             tb->cx = strlen(tb->lines_list[tb->cy]);
109         }
110
111         break;
112     }
113     case EC_DOWN: {
114         if (!tb->lines_list[tb->cy + 1]) {
115             if (!add_empty_line(tb)) {
116                 break;
117             }
118         }
119
120         tb->cy++;
121         break;
122     }
123     case EC_UP:
124         if (tb->cy > 0) {
125             tb->cy--;
126         }
127         break;
128     case EC_RIGHT: {
129 #ifdef JP
130         if (iskanji(tb->lines_list[tb->cy][tb->cx])) {
131             tb->cx++;
132         }
133 #endif
134         tb->cx++;
135         int len = strlen(tb->lines_list[tb->cy]);
136         if (len < tb->cx) {
137             tb->cx = len;
138             if (!tb->lines_list[tb->cy + 1]) {
139                 if (!add_empty_line(tb)) {
140                     break;
141                 }
142             }
143
144             tb->cy++;
145             tb->cx = 0;
146         }
147
148         break;
149     }
150     case EC_BOL:
151         tb->cx = 0;
152         break;
153     case EC_EOL:
154         tb->cx = strlen(tb->lines_list[tb->cy]);
155         break;
156     case EC_PGUP:
157         while (0 < tb->cy && tb->upper <= tb->cy) {
158             tb->cy--;
159         }
160
161         while (0 < tb->upper && tb->cy + 1 < tb->upper + tb->hgt) {
162             tb->upper--;
163         }
164
165         break;
166     case EC_PGDOWN:
167         while (tb->cy < tb->upper + tb->hgt) {
168             if (!tb->lines_list[tb->cy + 1]) {
169                 if (!add_empty_line(tb)) {
170                     break;
171                 }
172             }
173
174             tb->cy++;
175         }
176
177         tb->upper = tb->cy;
178         break;
179     case EC_TOP:
180         tb->cy = 0;
181         break;
182     case EC_BOTTOM:
183         while (true) {
184             if (!tb->lines_list[tb->cy + 1]) {
185                 if (!add_empty_line(tb)) {
186                     break;
187                 }
188             }
189
190             tb->cy++;
191         }
192
193         tb->cx = 0;
194         break;
195     case EC_CUT: {
196         copy_text_to_yank(tb);
197         if (tb->my == tb->cy) {
198             int bx1 = std::min(tb->mx, tb->cx);
199             int bx2 = std::max(tb->mx, tb->cx);
200             int len = strlen(tb->lines_list[tb->cy]);
201             if (bx2 > len) {
202                 bx2 = len;
203             }
204
205             kill_line_segment(tb, tb->cy, bx1, bx2, true);
206             tb->cx = bx1;
207         } else {
208             int by1 = std::min(tb->my, tb->cy);
209             int by2 = std::max(tb->my, tb->cy);
210
211             for (int y = by2; y >= by1; y--) {
212                 int len = strlen(tb->lines_list[y]);
213
214                 kill_line_segment(tb, y, 0, len, true);
215             }
216
217             tb->cy = by1;
218             tb->cx = 0;
219         }
220
221         tb->mark = 0;
222         tb->dirty_flags |= DIRTY_ALL;
223         tb->changed = true;
224         break;
225     }
226     case EC_COPY: {
227         copy_text_to_yank(tb);
228
229         /*
230          * Move cursor position to the end of the selection
231          *
232          * Pressing ^C ^V correctly duplicates the selection.
233          */
234         if (tb->my != tb->cy) {
235             tb->cy = std::max(tb->cy, tb->my);
236             if (!tb->lines_list[tb->cy + 1]) {
237                 if (!add_empty_line(tb)) {
238                     break;
239                 }
240             }
241
242             tb->cy++;
243             break;
244         }
245
246         tb->cx = std::max(tb->cx, tb->mx);
247         if (!tb->lines_list[tb->cy][tb->cx]) {
248             if (!tb->lines_list[tb->cy + 1]) {
249                 if (!add_empty_line(tb)) {
250                     break;
251                 }
252             }
253
254             tb->cy++;
255             tb->cx = 0;
256         }
257
258         break;
259     }
260     case EC_PASTE: {
261         chain_str_type *chain = tb->yank;
262         int len = strlen(tb->lines_list[tb->cy]);
263         if (!chain) {
264             break;
265         }
266         if (tb->cx > len) {
267             tb->cx = len;
268         }
269
270         if (tb->mark) {
271             tb->mark = 0;
272             tb->dirty_flags |= DIRTY_ALL;
273         }
274
275         while (chain) {
276             concptr yank_str = chain->s;
277             char buf[MAX_LINELEN];
278             int i;
279             char rest[MAX_LINELEN], *rest_ptr = rest;
280             for (i = 0; i < tb->cx; i++) {
281                 buf[i] = tb->lines_list[tb->cy][i];
282             }
283
284             strcpy(rest, &(tb->lines_list[tb->cy][i]));
285             while (*yank_str && i < MAX_LINELEN - 1) {
286                 buf[i++] = *yank_str++;
287             }
288
289             buf[i] = '\0';
290             chain = chain->next;
291             if (chain || tb->yank_eol) {
292                 if (!insert_return_code(tb)) {
293                     break;
294                 }
295                 string_free(tb->lines_list[tb->cy]);
296                 tb->lines_list[tb->cy] = string_make(buf);
297                 tb->cx = 0;
298                 tb->cy++;
299
300                 continue;
301             }
302
303             tb->cx = strlen(buf);
304             while (*rest_ptr && i < MAX_LINELEN - 1) {
305                 buf[i++] = *rest_ptr++;
306             }
307
308             buf[i] = '\0';
309             string_free(tb->lines_list[tb->cy]);
310             tb->lines_list[tb->cy] = string_make(buf);
311             break;
312         }
313
314         tb->dirty_flags |= DIRTY_ALL;
315         tb->dirty_flags |= DIRTY_EXPRESSION;
316         tb->changed = true;
317         break;
318     }
319     case EC_BLOCK: {
320         if (tb->mark) {
321             tb->mark = 0;
322             tb->dirty_flags |= DIRTY_ALL;
323             break;
324         }
325
326         tb->mark = MARK_MARK;
327         if (com_id == tb->old_com_id) {
328             int tmp = tb->cy;
329             tb->cy = tb->my;
330             tb->my = tmp;
331             tmp = tb->cx;
332             tb->cx = tb->mx;
333             tb->mx = tmp;
334             tb->dirty_flags |= DIRTY_ALL;
335             break;
336         }
337
338         int len = strlen(tb->lines_list[tb->cy]);
339
340         tb->my = tb->cy;
341         tb->mx = tb->cx;
342         if (tb->cx > len) {
343             tb->mx = len;
344         }
345         break;
346     }
347     case EC_KILL_LINE: {
348         int len = strlen(tb->lines_list[tb->cy]);
349         if (tb->cx > len) {
350             tb->cx = len;
351         }
352
353         if (tb->mark) {
354             tb->mark = 0;
355             tb->dirty_flags |= DIRTY_ALL;
356         }
357
358         if (tb->old_com_id != com_id) {
359             kill_yank_chain(tb);
360             tb->yank = nullptr;
361         }
362
363         if (tb->cx < len) {
364             add_str_to_yank(tb, &(tb->lines_list[tb->cy][tb->cx]));
365             kill_line_segment(tb, tb->cy, tb->cx, len, false);
366             tb->dirty_line = tb->cy;
367             break;
368         }
369
370         if (tb->yank_eol) {
371             add_str_to_yank(tb, "");
372         }
373
374         tb->yank_eol = true;
375         do_editor_command(player_ptr, tb, EC_DELETE_CHAR);
376         break;
377     }
378     case EC_DELETE_CHAR: {
379         if (tb->mark) {
380             tb->mark = 0;
381             tb->dirty_flags |= DIRTY_ALL;
382         }
383
384 #ifdef JP
385         if (iskanji(tb->lines_list[tb->cy][tb->cx])) {
386             tb->cx++;
387         }
388 #endif
389         tb->cx++;
390         int len = strlen(tb->lines_list[tb->cy]);
391         if (len >= tb->cx) {
392             do_editor_command(player_ptr, tb, EC_BACKSPACE);
393             break;
394         }
395
396         if (tb->lines_list[tb->cy + 1]) {
397             tb->cy++;
398             tb->cx = 0;
399         } else {
400             tb->cx = len;
401             break;
402         }
403
404         do_editor_command(player_ptr, tb, EC_BACKSPACE);
405         break;
406     }
407     case EC_BACKSPACE: {
408         int len, i, j, k;
409         char buf[MAX_LINELEN];
410         if (tb->mark) {
411             tb->mark = 0;
412             tb->dirty_flags |= DIRTY_ALL;
413         }
414
415         len = strlen(tb->lines_list[tb->cy]);
416         if (len < tb->cx) {
417             tb->cx = len;
418         }
419
420         if (tb->cx == 0) {
421             if (tb->cy == 0) {
422                 break;
423             }
424             tb->cx = strlen(tb->lines_list[tb->cy - 1]);
425             strcpy(buf, tb->lines_list[tb->cy - 1]);
426             strcat(buf, tb->lines_list[tb->cy]);
427             string_free(tb->lines_list[tb->cy - 1]);
428             string_free(tb->lines_list[tb->cy]);
429             tb->lines_list[tb->cy - 1] = string_make(buf);
430
431             for (i = tb->cy; tb->lines_list[i + 1]; i++) {
432                 tb->lines_list[i] = tb->lines_list[i + 1];
433             }
434
435             tb->lines_list[i] = nullptr;
436             tb->cy--;
437             tb->dirty_flags |= DIRTY_ALL;
438             tb->dirty_flags |= DIRTY_EXPRESSION;
439             tb->changed = true;
440             break;
441         }
442
443         for (i = j = k = 0; tb->lines_list[tb->cy][i] && i < tb->cx; i++) {
444             k = j;
445 #ifdef JP
446             if (iskanji(tb->lines_list[tb->cy][i])) {
447                 buf[j++] = tb->lines_list[tb->cy][i++];
448             }
449 #endif
450             buf[j++] = tb->lines_list[tb->cy][i];
451         }
452
453         while (j > k) {
454             tb->cx--;
455             j--;
456         }
457
458         for (; tb->lines_list[tb->cy][i]; i++) {
459             buf[j++] = tb->lines_list[tb->cy][i];
460         }
461
462         buf[j] = '\0';
463         string_free(tb->lines_list[tb->cy]);
464         tb->lines_list[tb->cy] = string_make(buf);
465         tb->dirty_line = tb->cy;
466         check_expression_line(tb, tb->cy);
467         tb->changed = true;
468         break;
469     }
470     case EC_SEARCH_STR: {
471         byte search_dir;
472         tb->dirty_flags |= DIRTY_SCREEN;
473         search_dir = get_string_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str);
474
475         if (!search_dir) {
476             break;
477         }
478
479         if (search_dir == 1) {
480             do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
481         } else {
482             do_editor_command(player_ptr, tb, EC_SEARCH_BACK);
483         }
484
485         break;
486     }
487     case EC_SEARCH_FORW:
488         if (tb->search_o_ptr) {
489             search_for_object(player_ptr, tb, tb->search_o_ptr, true);
490             break;
491         }
492
493         if (tb->search_str && tb->search_str[0]) {
494             search_for_string(tb, tb->search_str, true);
495             break;
496         }
497
498         tb->dirty_flags |= DIRTY_NO_SEARCH;
499         break;
500
501     case EC_SEARCH_BACK: {
502         if (tb->search_o_ptr) {
503             search_for_object(player_ptr, tb, tb->search_o_ptr, false);
504             break;
505         }
506
507         if (tb->search_str && tb->search_str[0]) {
508             search_for_string(tb, tb->search_str, false);
509             break;
510         }
511
512         tb->dirty_flags |= DIRTY_NO_SEARCH;
513         break;
514     }
515     case EC_SEARCH_OBJ: {
516         tb->dirty_flags |= DIRTY_SCREEN;
517
518         if (!get_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) {
519             break;
520         }
521
522         do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
523         break;
524     }
525     case EC_SEARCH_DESTROYED: {
526         if (!get_destroyed_object_for_search(player_ptr, &tb->search_o_ptr, &tb->search_str)) {
527             tb->dirty_flags |= DIRTY_NO_SEARCH;
528             break;
529         }
530
531         do_editor_command(player_ptr, tb, EC_SEARCH_FORW);
532         break;
533     }
534     case EC_INSERT_OBJECT: {
535         autopick_type an_entry, *entry = &an_entry;
536         if (!entry_from_choosed_object(player_ptr, entry)) {
537             tb->dirty_flags |= DIRTY_SCREEN;
538             break;
539         }
540
541         tb->cx = 0;
542         if (!insert_return_code(tb)) {
543             break;
544         }
545         string_free(tb->lines_list[tb->cy]);
546         tb->lines_list[tb->cy] = autopick_line_from_entry(*entry);
547         tb->dirty_flags |= DIRTY_SCREEN;
548         break;
549     }
550     case EC_INSERT_DESTROYED: {
551         if (!tb->last_destroyed) {
552             break;
553         }
554
555         tb->cx = 0;
556         if (!insert_return_code(tb)) {
557             break;
558         }
559         string_free(tb->lines_list[tb->cy]);
560         tb->lines_list[tb->cy] = string_make(tb->last_destroyed);
561         tb->dirty_flags |= DIRTY_ALL;
562         tb->changed = true;
563         break;
564     }
565     case EC_INSERT_BLOCK: {
566         if (!can_insert_line(tb, 2)) {
567             break;
568         }
569         char expression[80];
570         strnfmt(expression, sizeof(expression), "?:[AND [EQU $RACE %s] [EQU $CLASS %s] [GEQ $LEVEL %02d]]",
571 #ifdef JP
572             rp_ptr->E_title, cp_ptr->E_title,
573 #else
574             rp_ptr->title, cp_ptr->title,
575 #endif
576             player_ptr->lev);
577         tb->cx = 0;
578         insert_return_code(tb);
579         string_free(tb->lines_list[tb->cy]);
580         tb->lines_list[tb->cy] = string_make(expression);
581         tb->cy++;
582         insert_return_code(tb);
583         string_free(tb->lines_list[tb->cy]);
584         tb->lines_list[tb->cy] = string_make("?:1");
585         tb->dirty_flags |= DIRTY_ALL;
586         tb->changed = true;
587         break;
588     }
589     case EC_INSERT_MACRO: {
590         draw_text_editor(player_ptr, tb);
591         term_erase(0, tb->cy - tb->upper + 1, tb->wid);
592         term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW, _("P:<トリガーキー>: ", "P:<Trigger key>: "));
593         if (!insert_macro_line(tb)) {
594             break;
595         }
596
597         tb->cx = 2;
598         tb->dirty_flags |= DIRTY_ALL;
599         tb->changed = true;
600         break;
601     }
602     case EC_INSERT_KEYMAP: {
603         draw_text_editor(player_ptr, tb);
604         term_erase(0, tb->cy - tb->upper + 1, tb->wid);
605         term_putstr(0, tb->cy - tb->upper + 1, tb->wid - 1, TERM_YELLOW,
606             format(_("C:%d:<コマンドキー>: ", "C:%d:<Keypress>: "), (rogue_like_commands ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG)));
607
608         if (!insert_keymap_line(tb)) {
609             break;
610         }
611
612         tb->cx = 2;
613         tb->dirty_flags |= DIRTY_ALL;
614         tb->changed = true;
615         break;
616     }
617     case EC_CL_AUTOPICK:
618         toggle_command_letter(tb, DO_AUTOPICK);
619         break;
620     case EC_CL_DESTROY:
621         toggle_command_letter(tb, DO_AUTODESTROY);
622         break;
623     case EC_CL_LEAVE:
624         toggle_command_letter(tb, DONT_AUTOPICK);
625         break;
626     case EC_CL_QUERY:
627         toggle_command_letter(tb, DO_QUERY_AUTOPICK);
628         break;
629     case EC_CL_NO_DISP:
630         toggle_command_letter(tb, DO_DISPLAY);
631         break;
632     case EC_IK_UNAWARE:
633         toggle_keyword(tb, FLG_UNAWARE);
634         break;
635     case EC_IK_UNIDENTIFIED:
636         toggle_keyword(tb, FLG_UNIDENTIFIED);
637         break;
638     case EC_IK_IDENTIFIED:
639         toggle_keyword(tb, FLG_IDENTIFIED);
640         break;
641     case EC_IK_STAR_IDENTIFIED:
642         toggle_keyword(tb, FLG_STAR_IDENTIFIED);
643         break;
644     case EC_KK_WEAPONS:
645         toggle_keyword(tb, FLG_WEAPONS);
646         break;
647     case EC_KK_FAVORITE_WEAPONS:
648         toggle_keyword(tb, FLG_FAVORITE_WEAPONS);
649         break;
650     case EC_KK_ARMORS:
651         toggle_keyword(tb, FLG_ARMORS);
652         break;
653     case EC_KK_MISSILES:
654         toggle_keyword(tb, FLG_MISSILES);
655         break;
656     case EC_KK_DEVICES:
657         toggle_keyword(tb, FLG_DEVICES);
658         break;
659     case EC_KK_LIGHTS:
660         toggle_keyword(tb, FLG_LIGHTS);
661         break;
662     case EC_KK_JUNKS:
663         toggle_keyword(tb, FLG_JUNKS);
664         break;
665     case EC_KK_CORPSES:
666         toggle_keyword(tb, FLG_CORPSES);
667         break;
668     case EC_KK_SPELLBOOKS:
669         toggle_keyword(tb, FLG_SPELLBOOKS);
670         break;
671     case EC_KK_SHIELDS:
672         toggle_keyword(tb, FLG_SHIELDS);
673         break;
674     case EC_KK_BOWS:
675         toggle_keyword(tb, FLG_BOWS);
676         break;
677     case EC_KK_RINGS:
678         toggle_keyword(tb, FLG_RINGS);
679         break;
680     case EC_KK_AMULETS:
681         toggle_keyword(tb, FLG_AMULETS);
682         break;
683     case EC_KK_SUITS:
684         toggle_keyword(tb, FLG_SUITS);
685         break;
686     case EC_KK_CLOAKS:
687         toggle_keyword(tb, FLG_CLOAKS);
688         break;
689     case EC_KK_HELMS:
690         toggle_keyword(tb, FLG_HELMS);
691         break;
692     case EC_KK_GLOVES:
693         toggle_keyword(tb, FLG_GLOVES);
694         break;
695     case EC_KK_BOOTS:
696         toggle_keyword(tb, FLG_BOOTS);
697         break;
698     case EC_OK_COLLECTING:
699         toggle_keyword(tb, FLG_COLLECTING);
700         break;
701     case EC_OK_BOOSTED:
702         toggle_keyword(tb, FLG_BOOSTED);
703         break;
704     case EC_OK_MORE_DICE:
705         toggle_keyword(tb, FLG_MORE_DICE);
706         break;
707     case EC_OK_MORE_BONUS:
708         toggle_keyword(tb, FLG_MORE_BONUS);
709         break;
710     case EC_OK_WORTHLESS:
711         toggle_keyword(tb, FLG_WORTHLESS);
712         break;
713     case EC_OK_ARTIFACT:
714         toggle_keyword(tb, FLG_ARTIFACT);
715         break;
716     case EC_OK_EGO:
717         toggle_keyword(tb, FLG_EGO);
718         break;
719     case EC_OK_GOOD:
720         toggle_keyword(tb, FLG_GOOD);
721         break;
722     case EC_OK_NAMELESS:
723         toggle_keyword(tb, FLG_NAMELESS);
724         break;
725     case EC_OK_AVERAGE:
726         toggle_keyword(tb, FLG_AVERAGE);
727         break;
728     case EC_OK_RARE:
729         toggle_keyword(tb, FLG_RARE);
730         break;
731     case EC_OK_COMMON:
732         toggle_keyword(tb, FLG_COMMON);
733         break;
734     case EC_OK_WANTED:
735         toggle_keyword(tb, FLG_WANTED);
736         break;
737     case EC_OK_UNIQUE:
738         toggle_keyword(tb, FLG_UNIQUE);
739         break;
740     case EC_OK_HUMAN:
741         toggle_keyword(tb, FLG_HUMAN);
742         break;
743     case EC_OK_UNREADABLE:
744         toggle_keyword(tb, FLG_UNREADABLE);
745         add_keyword(tb, FLG_SPELLBOOKS);
746         break;
747     case EC_OK_REALM1:
748         toggle_keyword(tb, FLG_REALM1);
749         add_keyword(tb, FLG_SPELLBOOKS);
750         break;
751     case EC_OK_REALM2:
752         toggle_keyword(tb, FLG_REALM2);
753         add_keyword(tb, FLG_SPELLBOOKS);
754         break;
755     case EC_OK_FIRST:
756         toggle_keyword(tb, FLG_FIRST);
757         add_keyword(tb, FLG_SPELLBOOKS);
758         break;
759     case EC_OK_SECOND:
760         toggle_keyword(tb, FLG_SECOND);
761         add_keyword(tb, FLG_SPELLBOOKS);
762         break;
763     case EC_OK_THIRD:
764         toggle_keyword(tb, FLG_THIRD);
765         add_keyword(tb, FLG_SPELLBOOKS);
766         break;
767     case EC_OK_FOURTH:
768         toggle_keyword(tb, FLG_FOURTH);
769         add_keyword(tb, FLG_SPELLBOOKS);
770         break;
771     }
772
773     tb->old_com_id = com_id;
774     return APE_QUIT;
775 }