OSDN Git Service

c69642ac9dac98d581487b3f60d32544d3601a54
[nazghul-jp/nazghul-jp.git] / src / cmd.c
1 // nazghul - an old-school RPG engine
2 // Copyright (C) 2002, 2003 Gordon McNutt
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License as published by the Free
6 // Software Foundation; either version 2 of the License, or (at your option)
7 // any later version.
8 //
9 // This program is distributed in the hope that it will be useful, but WITHOUT
10 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12 // more details.
13 //
14 // You should have received a copy of the GNU General Public License along with
15 // this program; if not, write to the Free Foundation, Inc., 59 Temple Place,
16 // Suite 330, Boston, MA 02111-1307 USA
17 //
18 // Gordon McNutt
19 // gmcnutt@users.sourceforge.net
20 //
21
22 #include "cmd.h"
23 #include "../config.h" /* for USE_SKILLS */
24 #include "conv.h"
25 #include "place.h"
26 #include "constants.h"
27 #include "file.h"
28 #include "foogod.h"
29 #include "images.h"
30 #include "sprite.h"
31 #include "los.h"
32 #include "astar.h"
33 #include "common.h"
34 #include "screen.h"
35 #include "status.h"
36 #include "player.h"
37 #include "sky.h"
38 #include "map.h"
39 #include "wq.h"
40 #include "foogod.h"
41 #include "combat.h"
42 #include "cursor.h"
43 #include "Arms.h"
44 #include "event.h"
45 #include "wind.h"
46 #include "Container.h"
47 #include "dup_constants.h"
48 #include "cmdwin.h"
49 #include "vehicle.h"
50 #include "terrain.h"
51 #include "vmask.h"
52 #include "session.h"
53 #include "sched.h"
54 #include "conv.h"
55 #include "log.h"
56 #include "factions.h"
57 #include "result.h"
58 #include "dice.h"
59 #include "menus.h"
60 #include "kern_intvar.h"
61 #include "skill.h"
62 #include "skill_set.h"
63 #include "skill_set_entry.h"
64 #include "templ.h"
65 #include "occ.h"
66 #include "nazghul.h"  // for DeveloperMode
67 #include "ztats.h"
68 #include "terrain_editor.h"
69
70 #define DEBUG
71 #include "debug.h"
72
73 #include <string.h>
74 #include <stdlib.h>
75 #include <assert.h>
76 #include <ctype.h>
77 #include <unistd.h>     // getpid()
78 #include <errno.h>
79
80 #define ESCAPE_CHARACTER 110
81
82 /* Disabling the '>' command when standing over a subplace. This is generally
83  * not useful and can be abused for some towns. */
84 #ifndef ENABLE_TOWN_ZOOM_IN
85 #define ENABLE_TOWN_ZOOM_IN 0
86 #endif
87
88 /* SAM: Using this typedef below */
89 typedef void (*v_fncptr_iiv_t) (struct place *, int x, int y, void * v);
90 typedef int (*i_fncptr_iiv_t) (struct place *, int x, int y, void * v);
91
92
93 /**
94  * Struct used by the movecursor function and it's mouse-handling counterparts
95  * for commands which prompt the player to select a target from the map. 
96  */
97 struct movecursor_data {
98         v_fncptr_iiv_t each_tile_func;   /* called when cursor moves         */
99         i_fncptr_iiv_t each_target_func; /* called on 'enter' or leftclick   */
100         struct list *loc_list;           /* quick target list                */
101         struct list *cur_loc;            /* current target from list         */
102         int jump;                        /* distance to jump cursor          */
103         void *data;                      /* caller data passed to callbacks  */
104         char abort : 1;                  /* command was aborted              */
105 };
106
107 /* fwd decls */
108
109 #ifdef USE_SKILLS
110 static class Character *cmd_front_end(class Character *pc, const char *cmdstr);
111 #endif
112 static int cmd_eval_and_log_result(int result);
113 static int select_target_rlcb(struct place *place,
114                               int ox, int oy, int *x, int *y,
115                               int range,
116                               struct list *suggest,
117                               v_fncptr_iiv_t each_tile_func,
118                               i_fncptr_iiv_t each_target_func);
119
120 /* functions */
121
122 static class Character * cmdAnyPartyMemberEngagedInTask(void)
123 {
124     int num_pcs = player_party->getSize();
125     for (int i = 0; i < num_pcs; i++) {
126         class Character *pc = player_party->getMemberAtIndex(i);
127         if (pc->engagedInTask()) {
128             return pc;
129         }
130     }
131     return NULL;
132 }
133
134 int dirkey(struct KeyHandler *kh, int key, int keymod)
135 {
136         int *dir = (int *) kh->data;
137
138         if (key >= KEY_SOUTHWEST && key <= KEY_NORTHEAST) {
139                 *dir = keyToDirection(key);
140                 return 1;
141         }
142
143         if (key == SDLK_ESCAPE) {
144                 *dir = key;
145                 return 1;
146         }
147
148         /* Special case: let '.' mean KEY_HERE for the numeric keypad
149          * challenged. */
150         if (key == '.') {
151                 *dir = keyToDirection(KEY_HERE);
152                 return 1;
153         }
154
155         return 0;
156 }
157
158 int cardinaldirkey(struct KeyHandler *kh, int key, int keymod)
159 {
160         int *dir = (int *) kh->data;
161
162         switch (key) {
163         case KEY_NORTH:
164         case KEY_SOUTH:
165         case KEY_EAST:
166         case KEY_WEST:
167                 *dir = keyToDirection(key);
168                 return 1;
169         }
170
171         if (key == SDLK_ESCAPE) {
172                 *dir = key;
173                 return 1;
174         }
175
176         return 0;
177 }
178
179 int yesnokey(struct KeyHandler * kh, int key, int keymod)
180 {
181         int *yesno = (int *) kh->data;
182
183         switch (key) {
184         case 'y':
185         case 'Y':
186                 *yesno = 'y';
187                 return 1;
188         case 'n':
189         case 'N':
190         case CANCEL:
191                 *yesno = 'n';
192                 return 1;
193         default:
194                 return 0;
195         }
196 }
197
198 enum get_number_state {
199         GN_ALL,
200         GN_ZERO,
201         GN_SOME,
202         GN_CANCEL
203 };
204
205 /* Max number getnum() will accept */
206 const int MAX_GETNUM = 999999999;
207
208 struct get_number_info {
209         int digit;
210         int state;
211         char *prompt;
212 };
213
214 struct get_char_info {
215         const char *string;
216         char c;
217         int state;
218         char *prompt;
219 };
220
221 struct get_spell_name_data {
222         char spell_name[MAX_WORDS_IN_SPELL_NAME + 1];
223         const char *prompt;
224         char *ptr;
225         int n;
226         int state;
227 };
228
229 int getnum(struct KeyHandler *kh, int key, int keymod)
230 {
231         struct get_number_info *info;
232
233         info = (struct get_number_info *) kh->data;
234
235         switch (info->state) {
236         case GN_ALL:
237                 if (key == CANCEL) {
238                         cmdwin_pop();
239                         info->digit = 0;
240                         info->state = GN_CANCEL;
241                         return 1;
242                 }
243                 if (key == '\n') {
244                         cmdwin_pop();
245                         return 1;
246                 }
247                 if (key == '0') {
248                         cmdwin_pop();
249                         cmdwin_push("0");
250                         info->digit = 0;
251                         info->state = GN_ZERO;
252                         return 0;
253                 }
254                 if (isdigit(key)) {
255                         cmdwin_pop();
256                         info->digit = info->digit * 10 + key - '0';
257                         cmdwin_push("%c", key);
258                         info->state = GN_SOME;
259                         return 0;
260                 }
261                 break;
262         case GN_ZERO:
263                 if (key == CANCEL) {
264                         info->digit = 0;
265                         info->state = GN_CANCEL;
266                         return 1;
267                 }
268                 if (key == '\n') {
269                         return 1;
270                 }
271                 if (key == '\b') {
272                         cmdwin_pop();
273                         if (info->prompt)
274                                 cmdwin_spush(info->prompt);
275                         info->state = GN_ALL;
276                         return 0;
277                 }
278                 if (key == '0')
279                         return 0;
280                 if (isdigit(key)) {
281                         cmdwin_pop();
282                         info->digit = info->digit * 10 + key - '0';
283                         cmdwin_push("%c", key);
284                         info->state = GN_SOME;
285                         return 0;
286                 }
287                 break;
288         case GN_SOME:
289                 if (key == CANCEL) {
290                         info->digit = 0;
291                         info->state = GN_CANCEL;
292                         return 1;
293                 }
294                 if (key == '\n') {
295                         return 1;
296                 }
297                 if (key == '\b') {
298                         info->digit = info->digit - (info->digit % 10);
299                         info->digit /= 10;
300                         cmdwin_pop();
301                         if (info->digit == 0) {
302                                 info->state = GN_ALL;
303                                 if (info->prompt)
304                                         cmdwin_spush(info->prompt);
305                         }
306                         return 0;
307                 }
308                 if (isdigit(key)) {
309                         int keyval = key - '0';
310                         if ((MAX_GETNUM - keyval) >= info->digit) {
311                                 info->digit = info->digit * 10 + keyval;
312                                 cmdwin_push("%c", key);
313                         }
314                         return 0;
315                 }
316                 break;
317         }
318
319         return 0;
320 }
321
322 int getdigit(struct KeyHandler * kh, int key, int keymod)
323 {
324         struct get_number_info *info;
325
326         info = (struct get_number_info *) kh->data;
327         
328         if (key == CANCEL) {
329                 cmdwin_pop();
330                 info->digit = 0;
331                 return 1;
332         }
333
334         if (isdigit(key)) {
335                 cmdwin_pop();
336                 info->digit = key - '0';
337                 if (info->digit != 0)
338                         cmdwin_push("%c", key);
339                 return 1;
340         }
341         
342         return 0;
343 }
344
345 static int cmd_getchar(struct KeyHandler * kh, int key, int keymod)
346 {
347         struct get_char_info *info;
348
349         info = (struct get_char_info *) kh->data;
350         
351         if (key == CANCEL) {
352                 cmdwin_pop();
353                 info->c = 0;
354                 return 1;
355         }
356
357         if (strchr(info->string, key)) {
358                 cmdwin_pop();
359                 info->c = key;
360                 cmdwin_push("%c", key);
361                 return 1;
362         }
363         
364         return 0;        
365 }
366
367 int anykey(struct KeyHandler * kh, int key, int keymod)
368 {
369         return 1;
370 }
371
372 int scroller(struct KeyHandler * kh, int key, int keymod)
373 {
374         struct ScrollerContext *context;
375         context = (struct ScrollerContext *) kh->data;
376
377         switch (key) {
378         case KEY_NORTH:
379                 statusScroll(ScrollUp);
380                 break;
381         case KEY_SOUTH:
382                 statusScroll(ScrollDown);
383                 break;
384         case KEY_EAST:
385                 statusScroll(ScrollRight);
386                 break;
387         case KEY_WEST:
388                 statusScroll(ScrollLeft);
389                 break;
390         case SDLK_PAGEUP:
391                 statusScroll(ScrollPageUp);
392                 break;
393         case SDLK_PAGEDOWN:
394                 statusScroll(ScrollPageDown);
395                 break;
396         case SDLK_RETURN:
397         case SDLK_SPACE:
398         case KEY_HERE:
399         case '\n':
400                 if (context != NULL) {
401                         context->selection =
402                                 statusGetSelected(context->selector);
403                 }
404                 return 1;
405         case SDLK_ESCAPE:
406         case 'q':
407                 if (context)
408                         context->abort = 1;
409                 return 1;
410         case 'm':
411                 if (context && context->mixing) {
412                         context->done = 1;
413                         return 1;
414                 }
415                 break;
416         default:
417                 break;
418         }
419
420         return 0;
421 }
422
423 bool mouse_button_cursor(struct MouseButtonHandler *mh, SDL_MouseButtonEvent *event)
424 {
425         struct movecursor_data * data
426                 = (struct movecursor_data *) mh->data;
427         int mx = event->x;
428         int my = event->y;
429
430         /* Off-map? */
431         if (mapScreenToPlaceCoords(&mx, &my)) {
432                 return false;
433         }
434
435         /* Did the crosshair move? */
436         if (Session->crosshair->getX() != mx
437             || Session->crosshair->getY() != my) {
438
439                 /* turn on range shading after the first move */
440                 Session->crosshair->shadeRange(true);
441
442                 /* Move the crosshair */
443                 Session->crosshair->move(mx - Session->crosshair->getX(),
444                                          my - Session->crosshair->getY());
445                 mapSetDirty();
446
447                 /* Need to run our visitor function on each tile? */
448                 if (data->each_tile_func) {
449                         data->each_tile_func(Session->crosshair->getPlace(),
450                                              Session->crosshair->getX(),
451                                              Session->crosshair->getY(),
452                                              data->data);
453                 }
454
455         }
456
457         /* target selected? */
458         if (event->button == SDL_BUTTON_LEFT) {
459                 if (data->each_target_func) {
460                         return data->each_target_func(Session->crosshair->getPlace(),
461                                                       Session->crosshair->getX(),
462                                                       Session->crosshair->getY(),
463                                                       data->data);
464                 }
465                 return 1; /* target selected */
466         }
467
468
469         return false;
470 }
471
472 bool mouse_motion_cursor(struct MouseMotionHandler *mh, SDL_MouseMotionEvent *event)
473 {
474         struct movecursor_data * data
475                 = (struct movecursor_data *) mh->data;
476         int mx = event->x;
477         int my = event->y;
478
479         /* Off-map? */
480         if (mapScreenToPlaceCoords(&mx, &my)) {
481                 return false;
482         }
483         
484         /* Did the crosshair NOT move? */
485         if (Session->crosshair->getX() == mx
486             && Session->crosshair->getY() == my) {
487                 return false;
488         }
489
490         /* turn on range shading after the first move */
491         Session->crosshair->shadeRange(true);
492
493         /* Move the crosshair */
494         Session->crosshair->move(mx - Session->crosshair->getX(),
495                                  my - Session->crosshair->getY());
496         mapSetDirty();
497
498         /* Need to run our visitor function on each tile? */
499         if (data->each_tile_func) {
500                 data->each_tile_func(Session->crosshair->getPlace(),
501                                      Session->crosshair->getX(),
502                                      Session->crosshair->getY(),
503                                      data->data);
504         }
505
506         /* Mouse dragging? */
507         if (event->state & SDL_BUTTON(1)
508             && data->each_target_func) {
509                 return data->each_target_func(Session->crosshair->getPlace(),
510                                               Session->crosshair->getX(),
511                                               Session->crosshair->getY(),
512                                               data->data);
513         }
514
515
516         return false;
517 }
518
519 /**
520  * movecursor - move the crosshair around, possibly running a function on each
521  * tile entered by the crosshair or on each tile selected
522  */
523 int movecursor(struct KeyHandler * kh, int key, int keymod)
524 {
525         int moved = 0;
526         struct movecursor_data * data
527                 = (struct movecursor_data *) kh->data;
528   
529         /* target selected? */
530         switch (key) {
531         case SDLK_RETURN:
532         case SDLK_SPACE:
533         case KEY_HERE:
534         case '\n':
535                 if (data->each_target_func) {
536                         return data->each_target_func(Session->crosshair->getPlace(),
537                                                       Session->crosshair->getX(),
538                                                       Session->crosshair->getY(),
539                                                       data->data);
540                 }
541                 return 1; /* target selected */
542         default:
543                 break;
544         }
545   
546         /* crosshairs moved? */
547         if (keyIsDirection(key)) {
548                 int dir = keyToDirection(key);
549                 int dx = directionToDx(dir);
550                 int dy = directionToDy(dir);
551                 
552                 /* Brain-dead but simple way to clamp the jump distance to
553                  * range: iteratively back-off until it's ok. */
554                 while (OutOfRange == Session->crosshair->move(dx * data->jump, 
555                                                               dy * data->jump)
556                         && data->jump > 1) {
557                         data->jump--;
558                 }
559                 moved = 1;
560         } else if (isdigit(key)) {
561                 data->jump = key - '0';
562                 if (! data->jump)
563                         data->jump = 1; /* disallow zero */
564         } else {
565   
566                 struct list *old_loc = data->cur_loc;
567
568                 switch (key) {
569                         
570                 case SDLK_ESCAPE:
571                         /* Abort */
572                         data->abort = 1;
573                         return 1;   /* done */
574                         
575                 case '+':
576                 case '=':
577                 case 'n':
578                         /* Next target */
579                         if (data->loc_list
580                             && ! list_empty(data->loc_list)) {
581                                 data->cur_loc = data->cur_loc->next;
582                                 if (data->cur_loc == data->loc_list) {
583                                         /* wrap around */
584                                         data->cur_loc = 
585                                                 data->cur_loc->next;
586                                 }
587                         }
588                         break;
589                         
590                 case '-':
591                 case 'p':
592                         /* Previous target */
593                         if (data->loc_list
594                             && ! list_empty(data->loc_list)) {
595                                 data->cur_loc = data->cur_loc->prev;
596                                 if (data->cur_loc == data->loc_list) {
597                                         /* wrap around */
598                                         data->cur_loc = 
599                                                 data->cur_loc->prev;
600                                 }
601                         }
602                         break;
603                 default:
604                         break;
605                 }
606
607                 /* Target changed? */
608                 if (old_loc != data->cur_loc) {
609                         struct location_list *loc = 
610                                 (struct location_list*)data->cur_loc;
611                         Session->crosshair->move(loc->x - 
612                                                  Session->crosshair->getX(),
613                                                  loc->y - 
614                                                  Session->crosshair->getY());
615                         moved = 1;
616                 }
617         }
618
619         /* Cursor was moved? */
620         if (moved) {
621                 data->jump = 1;
622                 mapSetDirty();
623                 if (data->each_tile_func) {
624                         data->each_tile_func(Session->crosshair->getPlace(),
625                                              Session->crosshair->getX(),
626                                              Session->crosshair->getY(),
627                                              data->data);
628                 }
629
630                 /* turn on range shading after the first move */
631                 Session->crosshair->shadeRange(true);
632         }
633
634         return 0;   /* not done */
635 }
636
637 struct inv_entry *ui_select_item(void)
638 {
639         struct inv_entry *ie;
640         struct KeyHandler kh;
641         struct ScrollerContext sc;
642
643         foogodSetHintText(SCROLLER_HINT);
644         foogodSetMode(FOOGOD_HINT);        
645
646         sc.selector = InventoryItem;
647         sc.selection = NULL;
648         kh.fx = scroller;
649         kh.data = &sc;
650
651         eventPushKeyHandler(&kh);
652         cmdwin_push("<ÁªÂò>");
653         eventHandle();
654         cmdwin_pop();
655         eventPopKeyHandler();
656
657         foogodSetMode(FOOGOD_DEFAULT);
658
659         ie = (struct inv_entry *) sc.selection;
660         if (ie == NULL) {
661                 cmdwin_push("²¿¤â¤·¤Ê¤¤¡ª");
662                 return NULL;
663         }
664
665         cmdwin_spush(ie->type->getName());
666
667         return ie;
668 }
669
670 class Character *select_party_member(void)
671 {
672         enum StatusMode omode;
673         class Character *character;
674
675         if (1 == player_party->getSize()) {
676                 character = player_party->getMemberByOrder(0);
677                 /* fixme: move to cmd_front_end? */
678                 cmdwin_spush("%s", character->getName());
679                 return character;
680         }
681
682         foogodSetHintText(SCROLLER_HINT);
683         foogodSetMode(FOOGOD_HINT);        
684         omode = statusGetMode();
685         statusSetMode(SelectCharacter);
686
687         struct KeyHandler kh;
688         struct ScrollerContext sc;
689         sc.selector = Character;
690         sc.selection = NULL;
691         kh.fx = scroller;
692         kh.data = &sc;
693
694         eventPushKeyHandler(&kh);
695         cmdwin_push("<ÁªÂò>");
696         eventHandle();
697         cmdwin_pop();
698         eventPopKeyHandler();
699
700         statusRepaint();
701
702         character = (class Character *) sc.selection;
703
704         if (character == NULL) {
705                 cmdwin_push("²¿¤â¤·¤Ê¤¤¡ª"); /* fixme: move to cmd_front_end? */
706                 /* Hack alert: this saves the caller from having to remember to
707                  * do this. Doing it unconditionally is undesirable because it
708                  * can cause status screen flashes if the old mode requires a
709                  * short status window and the next mode requires a tall
710                  * one. */
711         } else {
712                 /* fixme: move to cmd_front_end? */
713                 cmdwin_spush("%s", character->getName());
714         }
715
716         statusSetMode(omode);
717         foogodSetMode(FOOGOD_DEFAULT);
718
719         return character;
720 }
721
722 void getkey(void *data, int(*handler) (struct KeyHandler * kh, int key, int keymod))
723 {
724         struct KeyHandler kh;
725         kh.fx = handler;
726         kh.data = data;
727
728         eventPushKeyHandler(&kh);
729         eventHandle();
730         eventPopKeyHandler();
731 }
732
733 int ui_get_direction(void)
734 {
735         int dir;
736         cmdwin_push("<Êý¸þ>");
737         getkey(&dir, dirkey);
738         cmdwin_pop();
739         if (dir == CANCEL) {
740                 cmdwin_push("²¿¤â¤·¤Ê¤¤¡ª");
741         } else {
742                 cmdwin_spush(directionToString(dir));
743         }
744         return dir;
745 }
746
747 static void search_visitor(class Object *obj, void *arg)
748 {
749         class ObjectType *type = obj->getObjectType();
750         /* Caution: searching can destroy the object if it triggers traps; the
751          * arg should be protected by the caller. */
752         if (type && type->canSearch()) {
753                 type->search(obj, (class Object*)arg);
754         }
755 }
756
757 bool cmdSearch(class Character *pc)
758 {
759         int dir;
760         bool old_reveal;
761         int x, y, x2,  y2;
762         struct place *place = 0;
763
764         cmdwin_clear();
765         cmdwin_spush("õ¤¹");
766
767         /* FIXME: this is duplicated in cmdHandle(), these command functions
768          * all need to be cleaned up to ensure consistency. */
769         if (! pc) {
770                 if (player_party->get_num_living_members() == 1) {
771                         pc = player_party->get_first_living_member();
772                         cmdwin_spush("%s", pc->getName());
773                 } else {
774                         pc = select_party_member();
775                         if (pc == NULL) {
776                                 return false;
777                         }
778                 }
779         }
780
781         assert(pc);
782         place = pc->getPlace();
783         x = pc->getX();
784         y = pc->getY();
785
786         dir = ui_get_direction();
787         if (dir == CANCEL)
788                 return false;
789
790         x2 = x + directionToDx(dir);
791         y2 = y + directionToDy(dir);
792
793         /* Caution: searching can destroy the pc if it triggers traps. The
794          * following is iterative, so protect the pc from destruction until it
795          * completes. */
796         obj_inc_ref(pc);
797         place_for_each_object_at(place, x2, y2, search_visitor, pc);
798         obj_dec_ref(pc);
799
800         log_begin("");
801         old_reveal = Reveal;
802         Reveal = true;
803         place_describe(place, x2, y2, PLACE_DESCRIBE_ALL);
804         log_end("¤ò¸«¤Ä¤±¤¿¡£");
805         Reveal = old_reveal;
806         pc->decActionPoints(kern_intvar_get("AP_COST:search"));  // SAM: We may want a '-1' value here, to signify "all remaining AP"...
807         
808         return true;
809 }
810
811 static int cmdGetFilter(class Object *obj)
812 {
813         return (int)(obj->getObjectType() && 
814                      obj->getObjectType()->canGet());
815 }
816
817 bool cmdGet(class Object *actor)
818 {
819         class Object *item;
820         int dir;
821         int x, y;
822         
823         cmdwin_clear();
824         cmdwin_spush("¼è¤ë");
825         
826         dir = ui_get_direction();
827         
828         if (dir == CANCEL)
829                 return false;
830         
831         x = actor->getX() + directionToDx(dir);
832         y = actor->getY() + directionToDy(dir);
833         
834         item = place_get_filtered_object(actor->getPlace(), x, y, 
835         cmdGetFilter);
836         if (!item) {
837                 log_msg("¼è¤ë - ²¿¤â¤Ê¤¤¡ª");
838                 return false;
839         }
840         
841         log_begin_group();
842         
843         while (NULL != (item = place_get_filtered_object(
844                                 actor->getPlace(), 
845                                 x, y, cmdGetFilter)))
846         {
847                 item->getObjectType()->get(item, actor);
848                 //do not allow too much AP debt if in combat
849                 if ((combat_get_state() == COMBAT_STATE_FIGHTING)
850                                         && ((2 * actor->getActionPoints()) + actor->getSpeed() < 0))
851                 {
852                         break;   
853                 }
854         }
855         
856         log_end_group();
857         
858         mapSetDirty();
859         actor->runHook(OBJ_HOOK_GET_DONE, 0);
860         actor->decActionPoints(kern_intvar_get("AP_COST:get_item"));  // SAM: Better to have a number of AP by item type...
861         
862         
863         return true;
864 }
865
866 static void cmd_describe_inv_entry(struct inv_entry *ie, void *unused)
867 {
868         log_begin("...");
869         ie->type->describeType(ie->count);
870         log_end(NULL);
871 }
872
873 bool cmdOpen(class Character * pc)
874 {
875         int dir, x, y;
876         class Object *mech;
877         class Container *container;
878
879         cmdwin_clear();
880         cmdwin_spush("³«¤¯");
881
882         // Get the party member who will open the container (in combat mode
883         // this is passed in as a parameter).
884         if (pc) {
885                 cmdwin_spush(pc->getName());
886         } else {
887                 pc = select_party_member();
888                 if (pc == NULL) {
889                         return false;
890                 }
891         }
892
893         dir = ui_get_direction();
894         if (dir == CANCEL)
895                 return false;
896
897         if (pc) {
898                 x = place_wrap_x(pc->getPlace(), 
899                                  pc->getX() + directionToDx(dir));
900                 y = place_wrap_y(pc->getPlace(), 
901                                  pc->getY() + directionToDy(dir));
902         } else {
903                 x = place_wrap_x(player_party->getPlace(),
904                                  player_party->getX() + directionToDx(dir));
905                 y = place_wrap_y(player_party->getPlace(),
906                                  player_party->getY() + directionToDy(dir));
907         }
908
909         /* Check for a mechanism */
910          mech = place_get_object(pc->getPlace(), x, y, mech_layer);
911
912          /* Check for a container */
913          container = (class Container *) place_get_object(Place, x, y, 
914                                                           container_layer);
915
916          /* ignore invisible objects unless Reveal is in effect */
917          if (! Reveal) {
918                  if (mech && ! mech->isVisible())
919                          mech = 0;
920                  if (container && ! container->isVisible())
921                          container = 0;
922          }
923
924          /* If both are present the user must select one */
925          if (mech && mech->getObjectType()->canOpen() && container) {
926
927                  enum StatusMode omode;
928                  struct stat_list_entry statlist[2];
929                  struct KeyHandler kh;
930                  struct ScrollerContext data;
931
932                  cmdwin_push("<ÁªÂò>");
933
934                  statlist[0].sprite = mech->getSprite();
935                  snprintf(statlist[0].line1, sizeof(statlist[0].line1), "%s",
936                           mech->getName());
937                  statlist[0].line2[0] = 0;
938                  statlist[0].data = mech;
939
940                  statlist[1].sprite = container->getSprite();
941                  snprintf(statlist[1].line1, sizeof(statlist[1].line2), "%s",
942                           container->getName());
943                  statlist[1].line2[0] = 0;
944                  statlist[1].data   = container;
945
946                  foogodSetHintText(SCROLLER_HINT);
947                  foogodSetMode(FOOGOD_HINT);        
948                  omode = statusGetMode();
949                  statusSetGenericList("ÂоÝ", 2, statlist);
950                  statusSetMode(GenericList);
951                  
952                  data.selection = NULL;
953                  data.selector  = Generic;
954                  kh.fx   = scroller;
955                  kh.data = &data;
956                  eventPushKeyHandler(&kh);
957                  eventHandle();
958                  eventPopKeyHandler();
959                  
960                  statusSetMode(omode);
961                  foogodSetMode(FOOGOD_DEFAULT);
962                  
963                  /* Disqualify the object NOT selected */
964                  if (data.selection == mech)
965                          container = NULL;
966                  else
967                          mech = NULL;
968
969                  cmdwin_pop();
970          }
971
972          /* Open a mechanism */
973          if (mech && mech->getObjectType()->canOpen()) {
974                  cmdwin_push("%s!", mech->getName());
975                  mech->getObjectType()->open(mech, pc);
976                  mapSetDirty();
977                  pc->runHook(OBJ_HOOK_OPEN_DONE, "p", mech);
978                  pc->decActionPoints(kern_intvar_get("AP_COST:open_mechanism"));
979                  return true;
980          }
981
982          /* Nothing to open */
983          if (NULL == container) {
984                  cmdwin_push("Ãæ»ß¡ª");
985                  log_msg("³«¤¯ - ²¿¤â¤Ê¤¤¡ª");
986                  return false;
987          }
988
989         /* Open Container */
990
991         log_begin_group();
992
993         pc->runHook(OBJ_HOOK_OPEN_DONE, "p", container);
994         pc->decActionPoints(kern_intvar_get("AP_COST:open_container"));
995         cmdwin_push("%s!", container->getName());
996
997         // Describe the contents of the container.
998         log_msg("¸«¤Ä¤±¤¿¤â¤Î:");
999         container->forEach(cmd_describe_inv_entry, NULL);
1000
1001         // Open the container (automagically spills all the contents onto the
1002         // map).
1003         container->open();
1004
1005         // --------------------------------------------------------------------
1006         // Delete container automatically on the combat map because if
1007         // containers are stacked (and they frequently are) then the top one
1008         // always gets selected and the player can't get at the ones
1009         // underneath. On the other hand, in towns I don't want to delete
1010         // people's furniture.
1011         //
1012         // Addendum: everything stated above still holds, but now corpse loot
1013         // can also get dropped on town maps outside, so I can no longer decide
1014         // whether or not to delete a container based on context. Furthermore,
1015         // I want all containers to behave the same way as much as
1016         // possible. This is an open issue and it may take some time and user
1017         // feedback to decide what best to do, so for now I'll simply always
1018         // remove containers after opening them.
1019         // --------------------------------------------------------------------
1020
1021         container->remove();
1022
1023         log_end_group();
1024
1025         mapSetDirty();
1026         return true;
1027 }
1028
1029 static bool cmd_nop_qh(struct QuitHandler *kh)
1030 {
1031         return false;
1032 }
1033
1034
1035 bool cmdQuit(void)
1036 {
1037         int yesno;
1038         struct QuitHandler qh;
1039
1040         /* Bugfix: if the player tries to close the window while we're in one
1041          * of our getkey() calls, we'll enter this function recursively,
1042          * messing up the prompts. So push a nop quit handler to prevent
1043          * that. Kind of a hack: why should this function "know" it is called
1044          * by the default quit handler? */
1045         qh.fx = cmd_nop_qh;
1046         eventPushQuitHandler(&qh);
1047         
1048         cmdwin_clear();
1049         cmdwin_spush("½ªÎ»¤¹¤ë");
1050         cmdwin_spush("<y/n>");
1051         getkey(&yesno, yesnokey);
1052         cmdwin_pop();
1053
1054         /* Cancel quit? */
1055         if (yesno == 'n') {
1056                 cmdwin_spush("Ãæ»ß¡ª");
1057                 Quit = false;
1058                 goto pop_qh;
1059         }
1060
1061         cmdwin_spush("Êݸ¤¹¤ë");
1062         cmdwin_spush("<y/n>");
1063         getkey(&yesno, yesnokey);
1064         cmdwin_pop();
1065
1066         /* Don't save? */
1067         if (yesno == 'n') {
1068                 cmdwin_spush("Êݸ¤·¤Ê¤¤¡ª");
1069                 Quit = true;
1070                 goto pop_qh;
1071         }
1072
1073         if (cmdSave()) {
1074             cmdwin_spush("Êݸ¤·¤¿¡ª");
1075             log_msg("¤µ¤è¤¦¤Ê¤é¡ª\n");
1076             Quit = true;
1077         } else {
1078             Quit = false;
1079         }
1080
1081  pop_qh:
1082         eventPopQuitHandler();
1083
1084         return Quit;
1085 }
1086
1087 void cmdAttack(void)
1088 {
1089         int dir;
1090         struct move_info info;
1091         struct combat_info cinfo;
1092
1093         // Initialize data structures.
1094         memset(&info, 0, sizeof(info));
1095         memset(&cinfo, 0, sizeof(cinfo));
1096         cinfo.move = &info;
1097         cinfo.defend = false;
1098                 
1099         // Get the direction
1100         cmdwin_clear();
1101         cmdwin_spush("¹¶·â¤¹¤ë");
1102         cmdwin_spush("<Êý¸þ>");
1103         getkey(&dir, cardinaldirkey);
1104         cmdwin_pop();
1105         if (dir == CANCEL) {
1106                 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1107                 return;
1108         }
1109         cmdwin_spush("%s", directionToString(dir));
1110
1111         // Get the npc party being attacked
1112         info.dx = directionToDx(dir);
1113         info.dy =  directionToDy(dir);;
1114         info.place = player_party->getPlace();
1115         info.x = place_wrap_x(info.place, player_party->getX() + info.dx);
1116         info.y = place_wrap_y(info.place, player_party->getY() + info.dy);
1117         info.npc_party = place_get_Party(info.place, info.x, info.y);
1118                                 
1119         if (info.npc_party == NULL) {
1120                 cmdwin_spush("ï¤â¤¤¤Ê¤¤¡ª");
1121                 log_msg("¹¶·â¤¹¤ë - Ã¯¤â¤¤¤Ê¤¤¡ª");
1122                 return;
1123         } 
1124         info.px = player_party->getX();
1125         info.py = player_party->getY();
1126
1127         cmdwin_spush("%s", info.npc_party->getName());
1128
1129         // If the npc is not hostile then get player confirmation.
1130         if (! are_hostile(info.npc_party, player_party)) {
1131                 int yesno;
1132                 cmdwin_spush("Ũ¤Ç¤Ê¤¤¼Ô¤ò¹¶·â¤¹¤ë");
1133                 cmdwin_spush("<y/n>");
1134                 getkey(&yesno, yesnokey);
1135                 cmdwin_pop();
1136                 if (yesno == 'n') {
1137                         cmdwin_spush("¤¤¤¤¤¨");
1138                         return;
1139                 }
1140                 cmdwin_spush("¤Ï¤¤");
1141
1142                 make_hostile(info.npc_party, player_party);
1143         }
1144
1145         // Log the attack.
1146         log_begin("");
1147         info.npc_party->describe();
1148         log_end("¤ò¹¶·â¤·¤¿¡£");
1149
1150         // Enter combat
1151         combat_enter(&cinfo);
1152 }
1153
1154 void cmdDeveloperEval(struct session *session)
1155 {
1156         unsigned int len = 1024;
1157         char *buf = (char*)calloc(len, sizeof(char));
1158         if (!buf) {
1159                 log_msg("Eval: not enough memory!");
1160                 return;
1161         }
1162
1163         cmdwin_clear();
1164         cmdwin_push("Eval:");
1165
1166         if (!ui_getline_filtered(buf, len, NULL)) {
1167                 log_msg("Eval: abort");
1168                 cmdwin_push("abort!");
1169                 goto cleanup;
1170         }
1171
1172         log_msg("Eval: %s", buf);
1173         session_eval(session, buf);
1174
1175  cleanup:
1176         free(buf);
1177 }
1178
1179 void cmdFire(void)
1180 {
1181         int dir;
1182
1183         cmdwin_clear();
1184         cmdwin_spush("ˤ·â¤¹¤ë");
1185
1186         class Vehicle *vehicle = player_party->getVehicle();
1187         if ((!vehicle ||
1188              !vehicle->getOrdnance())) {
1189                 // SAM: 
1190                 // In future, we may check for adjacent "cannon" 
1191                 // mechanisms here (as in U5).
1192                 cmdwin_spush("ˤ·â¤Ç¤­¤Ê¤¤¡ª");
1193                 log_msg("ˤ·â¤¹¤ë - Âçˤ¤¬¤Ê¤¤¡ª");
1194                 return;
1195         }
1196
1197         cmdwin_spush("%s", vehicle->getOrdnance()->getName());
1198         cmdwin_spush("<Êý¸þ>");
1199         getkey(&dir, dirkey);
1200         cmdwin_pop();
1201
1202         if (dir == CANCEL) {
1203                 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1204                 return;
1205         }
1206
1207         cmdwin_spush("%s", directionToString(dir));
1208         if (! vehicle->fire_weapon(directionToDx(dir), 
1209                                                  directionToDy(dir), 
1210                                                  player_party)) {
1211                 cmdwin_spush("¦ÌÌÊý¸þ¤Ç¤Ê¤¤¡ª");
1212                 log_msg("ˤ·â¤¹¤ë - Â¦ÌÌÊý¸þ¤Ç¤Ê¤¤¡ª");
1213                 return;
1214         }
1215 }
1216
1217 bool cmdReady(class Character * member)
1218 {
1219         bool committed = false;
1220         struct inv_entry *ie;
1221         struct KeyHandler kh;
1222         struct ScrollerContext sc;
1223         const char *msg = 0;
1224
1225         cmdwin_clear();
1226         cmdwin_spush("ÁõÈ÷¤¹¤ë");
1227
1228         // Select user
1229         if (member) {
1230                 cmdwin_spush("%s", member->getName());                
1231         } else {
1232                 member = select_party_member();
1233                 if (member == NULL)
1234                         return false;       
1235
1236                 if (member->isCharmed()) {
1237                         cmdwin_push("ËâË¡¤¬¤«¤±¤é¤ì¤Æ¤¤¤ë¡ª");
1238                         log_msg("ÁõÈ÷¤¹¤ë - ËâË¡¤¬¤«¤±¤é¤ì¤Æ¤¤¤ë¡ª");
1239                         return false;
1240                 }
1241
1242         }
1243
1244         log_begin_group();
1245         log_msg("%s¤ÎÁõÈ÷:", member->getName());
1246
1247         statusSelectCharacter(member->getOrder());
1248
1249         player_party->sortReadiedItems(member);
1250         foogodSetHintText(SCROLLER_HINT);
1251         foogodSetMode(FOOGOD_HINT);        
1252         statusSetMode(Ready);
1253         sc.selector = InventoryItem;
1254         kh.fx = scroller;
1255         kh.data = &sc;
1256         eventPushKeyHandler(&kh);
1257
1258         cmdwin_spush("<ÁªÂò/ESC>");
1259
1260         for (;;) {
1261
1262                 sc.selection = NULL;
1263
1264                 eventHandle();
1265                 cmdwin_pop();
1266
1267                 ie = (struct inv_entry *) sc.selection;
1268                 if (ie == NULL) {
1269                         cmdwin_spush("½ª¤¨¤¿¡ª");
1270                         break;
1271                 }
1272
1273                 committed = true;
1274
1275                 class ArmsType *arms = (class ArmsType *) ie->type;
1276
1277                 log_begin("%s - ", arms->getName());
1278
1279                 if (ie->ref && member->unready(arms)) {
1280                         msg = "³°¤·¤¿¡ª";
1281                         member->decActionPoints(arms->getRequiredActionPoints());
1282                         statusRepaint();
1283                 } else {
1284
1285                         switch (member->ready(arms)) {
1286                         case Character::Readied:
1287                                 statusRepaint();
1288                                 msg = "ÁõÈ÷¤·¤¿¡ª";
1289                                 member->decActionPoints(arms->getRequiredActionPoints());
1290            /* Move the readied item to the front of the
1291             * list for easy access next time, and to
1292             * percolate frequently-used items up to the
1293             * top. */
1294            //player_party->inventory->moveToFront(ie);
1295            /* After re-ordering the list, reset the status
1296             * viewer to synch it back up with the new
1297             * list. */
1298            //statusSetMode(Ready);
1299                                 break;
1300                         case Character::NoAvailableSlot:
1301                                 msg = "»ý¤Á¤­¤ì¤Ê¤¤¡ª";
1302                                 break;
1303                         case Character::WrongType:
1304                                 msg = "»È¤¨¤Ê¤¤¡ª";
1305                                 break;
1306                         case Character::TooHeavy:
1307                                 msg = "½Å¤¹¤®¤ë¡ª";
1308                                 break;
1309                         default:
1310                                 assert(false);
1311                                 break;
1312                         }
1313                 }
1314
1315                 cmdwin_spush("%s %s", arms->getName(), msg);
1316                 log_end(msg);
1317       
1318         //do not allow too much AP debt if in combat
1319                 if ((combat_get_state() == COMBAT_STATE_FIGHTING)
1320                                         && ((2 * member->getActionPoints()) + member->getSpeed() < 0))
1321                 {
1322                         break;   
1323                 }
1324       
1325         }
1326
1327         eventPopKeyHandler();
1328         statusSetMode(ShowParty);
1329         foogodSetMode(FOOGOD_DEFAULT);
1330
1331         if (committed) {
1332                 player_party->sortReadiedItems(member);
1333                 member->runHook(OBJ_HOOK_READY_DONE, 0);
1334         }
1335
1336         log_end_group();
1337
1338         return committed;
1339 }
1340
1341 static void cmd_init_movecursor_data(struct movecursor_data *data, 
1342                                      struct list *suggest)
1343 {
1344         struct list *entry = 0;
1345
1346         memset(data, 0, sizeof(*data));
1347         data->jump = 1;
1348
1349         if (! suggest)
1350                 return;
1351
1352         /* Copy the head of the list. */
1353         data->loc_list = suggest;
1354         data->cur_loc = data->loc_list;
1355
1356         /* Look for the crosshair in the suggest list. */
1357         list_for_each(suggest, entry) {
1358                 struct location_list *loc = 
1359                         (struct location_list*)entry;
1360                 if (loc->x == Session->crosshair->getX()
1361                     && loc->y == Session->crosshair->getY()) {
1362                         data->cur_loc = &loc->list;
1363                         break;
1364                 }
1365         }
1366 }
1367
1368 int select_target(int ox, int oy, int *x, int *y, int range, 
1369                   struct list *suggest)
1370 {
1371         return select_target_rlcb(Place, ox, oy, x, y, range, suggest, 0, 0);
1372 }
1373
1374 void ui_select_target_req_init(ui_select_target_req_t *req)
1375 {
1376         memset(req, 0, sizeof(*req));
1377         list_init(&req->suggest);
1378 }
1379
1380 static int select_target_rlcb(struct place *place, 
1381                               int ox, int oy, 
1382                               int *x, int *y,
1383                               int range,
1384                               struct list *suggest,
1385                               v_fncptr_iiv_t each_tile_func,
1386                               i_fncptr_iiv_t each_target_func)
1387 {
1388         ui_select_target_req_t req;
1389         int ret;
1390
1391         /* convert args to a targeting request */
1392         ui_select_target_req_init(&req);
1393         req.place = place;
1394         req.x1 = ox;
1395         req.y1 = oy;
1396         req.x2 = *x;
1397         req.y2 = *y;
1398         req.move = each_tile_func;
1399         req.select = each_target_func;
1400         req.tiles = templ_new_from_range(range);
1401         templ_set_origin(req.tiles, ox, oy);
1402         if (suggest) {
1403                 list_move(&req.suggest, suggest);
1404         }
1405         
1406         /* call generic target selection */
1407         ret = ui_select_target_generic(&req);
1408
1409         /* convert back */
1410         *x = req.x2;
1411         *y = req.y2;
1412         if (suggest) {
1413                 list_move(suggest, &req.suggest);
1414         }
1415         templ_unref(req.tiles);
1416
1417         return ret;
1418 }
1419
1420 int ui_select_target_generic(ui_select_target_req_t *req)
1421 {
1422         struct movecursor_data data;
1423         struct KeyHandler kh;
1424         struct MouseButtonHandler mbh;
1425         struct MouseMotionHandler mmh;
1426
1427         Session->crosshair->setZone(req->tiles);
1428         Session->crosshair->setViewportBounded(1);
1429         Session->crosshair->setOrigin(req->x1, req->y1);
1430         Session->crosshair->relocate(req->place, req->x2, req->y2);
1431         Session->show_boxes=1;
1432         mapSetDirty();
1433
1434         cmd_init_movecursor_data(&data, &req->suggest);
1435         data.each_tile_func   = req->move;
1436         data.each_target_func = req->select;
1437         data.data = req->data;
1438
1439         kh.fx   = movecursor;
1440         kh.data = &data;
1441   
1442         mbh.fx = mouse_button_cursor;
1443         mbh.data = &data;
1444
1445         mmh.fx = mouse_motion_cursor;
1446         mmh.data = &data;
1447
1448         eventPushMouseButtonHandler(&mbh);
1449         eventPushKeyHandler(&kh);
1450         cmdwin_spush("<ÂоÝ> (ESC¤ÇÃæ»ß)");
1451         eventHandle();
1452         cmdwin_pop();
1453         eventPopKeyHandler();
1454         eventPopMouseButtonHandler();
1455   
1456         Session->show_boxes=0;
1457         req->x2 = Session->crosshair->getX();
1458         req->y2 = Session->crosshair->getY();
1459         Session->crosshair->remove();
1460         Session->crosshair->setZone(0);
1461         mapSetDirty();
1462   
1463         if (data.abort) {
1464                 cmdwin_spush("½ª¤¨¤¿¡£");
1465                 return -1;
1466         }
1467   
1468         return 0;
1469 }
1470
1471 int select_target_with_doing(int ox, int oy, int *x, int *y,
1472                              int range,
1473                              v_fncptr_iiv_t each_tile_func,
1474                              i_fncptr_iiv_t each_target_func)
1475 {
1476         return select_target_rlcb(Place, ox, oy, x, y, range, 0, 
1477                                   each_tile_func, 
1478                                   each_target_func);
1479 }
1480
1481 bool cmdHandle(class Character * pc)
1482 {
1483         // SAM: Adding (H)andle command...
1484         int x;
1485         int y;
1486
1487         cmdwin_clear();
1488         cmdwin_spush("Áàºî¤¹¤ë");
1489
1490         if (pc) {
1491                 // A party member was specified as a parameter, so this must be
1492                 // combat mode. Use the party member's location as the origin.
1493                 x = pc->getX();
1494                 y = pc->getY();
1495                 cmdwin_spush("%s", pc->getName());
1496         } else {
1497                 // Must be party mode. Use the player party's location as the
1498                 // origin.
1499                 x = player_party->getX();
1500                 y = player_party->getY();
1501
1502                 // And find out what the party member is Handling (so we can
1503                 // print the name). If only one party member then select the
1504                 // only one.
1505                 if (player_party->get_num_living_members() == 1) {
1506                         pc = player_party->get_first_living_member();
1507                         cmdwin_spush("%s", pc->getName());
1508                 } else {
1509                         pc = select_party_member();
1510                         if (pc == NULL) {
1511                                 return false;
1512                         }
1513                 }
1514         }
1515
1516         // *** Pick a target ***
1517
1518         if (select_target(x, y, &x, &y, 1, 0) == -1)
1519                 return false;
1520
1521         // Try to find a mech
1522         class Object *mech;
1523         mech = place_get_object(Place, x, y, mech_layer);
1524         if (! mech 
1525             || ! mech->getObjectType()->canHandle()
1526             || (! mech->isVisible()            
1527                 && ! Reveal)) {
1528                 cmdwin_spush("²¿¤â¤Ê¤¤¡ª");
1529                 log_msg("Áàºî¤¹¤ë - ²¿¤â¤Ê¤¤¡ª");
1530                 return false;
1531         }
1532
1533         // Handle it (sometimes mechs are intentionally nameless so that they
1534         // remain hidden from x)amine and s)earch commands)
1535         const char *mechName=mech->getName();
1536         if (!mechName) {
1537                 mechName = "±£¤µ¤ì¤¿ÁõÃÖ";
1538         }
1539         cmdwin_spush("%s", mechName);
1540         log_msg("%s¤Ï%s¤òÁàºî¤·¤¿¡£", pc->getName(), mechName);
1541         mech->getObjectType()->handle(mech, pc);
1542         pc->runHook(OBJ_HOOK_HANDLE_DONE, "p", mech);
1543         pc->decActionPoints(kern_intvar_get("AP_COST:handle_mechanism"));
1544         mapSetDirty();
1545
1546         // I think the following was added to update LOS in cases where the
1547         // mech changed state and changed LOS. Not sure what happens in
1548         // character mode.
1549         //player_party->updateView();
1550
1551         return true;
1552 }
1553
1554 bool cmdUse(class Character * member, int flags)
1555 {
1556         struct inv_entry *ie;
1557         class ObjectType *item;
1558         int result;
1559
1560         cmdwin_clear();
1561         cmdwin_spush("»È¤¦");
1562
1563         // Select user
1564         if (flags & CMD_SELECT_MEMBER) {
1565                 member = select_party_member();
1566                 if (member == NULL)
1567                         return false;       
1568         } else {
1569                 assert(member);
1570                 cmdwin_spush("%s", member->getName());
1571         }
1572         statusSelectCharacter(member->getOrder());
1573
1574         // select item to use
1575         statusSetMode(Use);
1576         ie = ui_select_item();
1577         statusSetMode(ShowParty);
1578         if (ie == NULL) {
1579                 return false;
1580         }
1581
1582         /* warning: assume usable item came from player inventory; move it to
1583          * the front of the list so that frequently-used items percolate to the
1584          * top for easy selection by the player. Oh, and do this *before* using
1585          * it, since using it may delete the ie if it is a consumable item and
1586          * the last one in inventory. */
1587         player_party->inventory->moveToFront(ie);
1588
1589         item = ie->type;
1590         assert(item->isUsable());
1591
1592         // Use the item
1593         log_begin("%s: %s - ", member->getName(), item->getName());
1594         result = item->use(member);
1595         cmd_eval_and_log_result(result);
1596         log_end(0);
1597
1598         member->runHook(OBJ_HOOK_USE_DONE, "p", item);
1599
1600         // Item's appear to decrement AP in the script...
1601         //member->decActionPoints(kern_intvar_get("AP_COST:use_item"));
1602         statusRepaint();
1603
1604         return true;
1605 }
1606
1607 /* Helper function called by cmdNewOrder: */
1608 static void cmd_switch_party_leader(class Character *old_leader,
1609                                     class Character *new_leader)
1610 {
1611         new_leader->setLeader(true);
1612         old_leader->setLeader(false);
1613         old_leader->endTurn();
1614         old_leader->setControlMode(CONTROL_MODE_FOLLOW);
1615         player_party->setLeader(new_leader);
1616 }
1617
1618 void cmdNewOrder(void)
1619 {
1620         class Character *pc1, *pc2;
1621
1622         switch (player_party->getSize()) {
1623         case 0:
1624                 assert(0);
1625                 break;
1626         case 1:
1627                 log_msg("½ç½ø - ¤¢¤Ê¤¿¤·¤«¤¤¤Ê¤¤¡ª");
1628                 return;
1629         case 2:
1630                 pc1 = player_party->getMemberByOrder(0);
1631                 pc2 = player_party->getMemberByOrder(1);
1632                 goto swap;
1633         }
1634
1635         cmdwin_clear();
1636         cmdwin_spush("Æþ¤ìÂؤï¤ë");
1637
1638         // Set the mode now - before calling select_party_member - so that the
1639         // screen will not flash back to a short status window between the two
1640         // calls to select_party_member.
1641         statusSetMode(SelectCharacter);
1642
1643         pc1 = select_party_member();
1644         if (pc1 == NULL) {
1645                 statusSetMode(ShowParty);
1646                 return;
1647         }
1648
1649         cmdwin_spush("¤È");
1650
1651         pc2 = select_party_member();
1652         if (pc2 == NULL) {
1653                 statusSetMode(ShowParty);
1654                 return;
1655         }
1656
1657         statusSetMode(ShowParty);
1658  swap:
1659         player_party->switchOrder(pc1, pc2);
1660
1661         log_msg("½ç½ø: %s¤Ï%s¤ÈÆþ¤ìÂؤï¤Ã¤¿¡£", pc1->getName(),
1662                      pc2->getName());
1663
1664         // If one of the switched members was the party leader then make the
1665         // other one the new leader (unless the other one is dead or otherwise
1666         // incapable of being a party leader).
1667         if (pc1->isLeader() && pc2->canBeLeader()) {
1668                 cmd_switch_party_leader(pc1, pc2);
1669         } else if (pc2->isLeader() && pc1->canBeLeader()) {
1670                 cmd_switch_party_leader(pc2, pc1);
1671         }
1672
1673         statusRepaint();
1674 }
1675
1676 static void run_combat(bool camping, class Character * guard, int hours,
1677                        class Object *foe)
1678 {
1679         struct move_info minfo;
1680         struct combat_info cinfo;
1681
1682         assert(!foe || foe->isType(PARTY_ID));
1683
1684         memset(&minfo, 0, sizeof(minfo));
1685         minfo.place = Place;
1686         minfo.x = player_party->getX();
1687         minfo.y = player_party->getY();
1688         minfo.px = minfo.x;
1689         minfo.py = minfo.y;
1690         minfo.npc_party = (class Party*)foe;
1691
1692         memset(&cinfo, 0, sizeof(cinfo));
1693         cinfo.camping = camping;
1694         cinfo.guard = guard;
1695         cinfo.hours = hours;
1696         cinfo.move = &minfo;
1697
1698         // Is there an enemy?
1699         if (foe) {
1700                 // Yes, so I assume the player party is being attacked
1701                 // (currently this happens as a result of conversation). To
1702                 // setup the proper orientation of the parties I need to get
1703                 // the direction vector. The direction should be from the foe
1704                 // to the player.
1705                 cinfo.defend = true;
1706                 place_get_direction_vector(minfo.place, 
1707                                            foe->getX(), foe->getY(),
1708                                            minfo.x, minfo.y, 
1709                                            &minfo.dx, &minfo.dy);
1710         } else {
1711                 // No, so we're camping or zooming in. Party values are fine
1712                 // here.
1713                 minfo.dx = player_party->getDx();
1714                 minfo.dy = player_party->getDy();
1715         } 
1716
1717         combat_enter(&cinfo);
1718 }
1719
1720 struct talk_info {
1721         class Object *origin;
1722         class Object *nearest;
1723         int min_distance;
1724         int range;
1725         struct list suggest;
1726 };
1727
1728 /* cmd_talk_info_visitor - called on each object in the current place. Used by
1729  * cmdTalk() to find the nearest conversant and build a list of other available
1730  * conversants. */
1731 static void cmd_talk_info_visitor(class Object *obj, void *data)
1732 {
1733         struct location_list *entry = 0;
1734         int dist = 0;
1735         struct talk_info *info = 
1736                 (struct talk_info*)data;
1737
1738         if (! obj->getConversation())
1739                 return;
1740
1741         if (obj->isPlayerControlled())
1742                 return;
1743
1744         if (TimeStop)
1745                 return;
1746         
1747         if (! obj->isVisible() && ! Reveal)
1748                 return;
1749
1750         /* Filter out objects not in los of the subject */
1751         if (! place_in_los(info->origin->getPlace(),
1752                            info->origin->getX(),
1753                            info->origin->getY(),
1754                            obj->getPlace(),
1755                            obj->getX(),
1756                            obj->getY()))
1757                 return;
1758         
1759
1760         /* Filter out objects not in range of conversation. */
1761         dist = place_flying_distance(info->origin->getPlace(),
1762                                      info->origin->getX(),
1763                                      info->origin->getY(),
1764                                      obj->getX(),
1765                                      obj->getY());
1766
1767         if (dist > info->range)
1768                 return;
1769
1770         /* Add this conversant to the suggestion list. */
1771         entry = (struct location_list*)malloc(sizeof(*entry));
1772         assert(entry);
1773         entry->x = obj->getX();
1774         entry->y = obj->getY();
1775         list_add_tail(&info->suggest, &entry->list);
1776
1777         /* Remember the nearest conversant. */
1778         if (! info->nearest
1779             || dist < info->min_distance) {
1780                 info->nearest = obj;
1781                 info->min_distance = dist;
1782         }
1783 }
1784
1785 /* cmd_get_talk_info - find the nearest conversant and build the
1786  * 'suggest' list. */
1787 static class Object *cmd_get_talk_info(struct talk_info *info,
1788                                              class Object *member, 
1789                                              int range)
1790 {
1791         memset(info, 0, sizeof(info));
1792         info->origin = member;
1793         info->nearest = NULL;
1794         info->min_distance = 0;
1795         info->range = range;
1796         list_init(&info->suggest);
1797
1798         place_for_each_object(member->getPlace(), 
1799                               cmd_talk_info_visitor,
1800                               info);
1801
1802         return info->nearest;
1803 }
1804
1805 /* cmd_cleanup_talk_info - free the 'suggest' list. */
1806 static void cmd_cleanup_talk_info(struct talk_info *info)
1807 {
1808         struct list *entry;
1809         for (entry = info->suggest.next; entry != &info->suggest; ) {
1810                 struct location_list *loc = (struct location_list*)entry;
1811                 entry = entry->next;
1812                 list_remove(&loc->list);
1813                 free(loc);
1814         }
1815 }
1816
1817 void cmdTalk(Object *member)
1818 {
1819         struct conv *conv = NULL;
1820         class Object *obj, *conversant = NULL;
1821         int x, y;
1822         struct talk_info info;
1823         const int max_distance = 5;
1824
1825         // *** Prompt user & check if valid ***
1826
1827         cmdwin_clear();
1828         cmdwin_spush("Ïä¹");
1829
1830         if (! member) {
1831                 member = select_party_member();
1832                 if (! member)
1833                         return;
1834         }
1835
1836         // start cursor on nearest object with a conversation
1837         conversant = cmd_get_talk_info(&info, member, max_distance);
1838         if (! conversant) {
1839                 conversant = member;
1840         }
1841
1842         x = conversant->getX();
1843         y = conversant->getY();
1844
1845         if (select_target(member->getX(), member->getY(), 
1846                           &x, &y, max_distance, &info.suggest) == -1) {
1847                 goto cleanup;
1848         }
1849
1850         obj = place_get_object(Place, x, y, being_layer);
1851
1852         if (!obj) {
1853                 cmdwin_spush("ï¤â¤¤¤Ê¤¤¡ª");
1854                 log_msg("¿Í¤ÈÏ乤褦¤Ë¡ª");
1855                 goto cleanup;
1856         }
1857
1858         // This next bit was added to support talking to parties, where the
1859         // speaker is not the party itself.
1860         obj = obj->getSpeaker();
1861         if (! obj) {
1862                 cmdwin_spush("Ãæ»ß");
1863                 goto cleanup;
1864         }
1865
1866         if (TimeStop && !obj->isPlayerPartyMember()) {
1867                 cmdwin_spush("»þ¤¬»ß¤Þ¤Ã¤Æ¤¤¤ë¡ª");
1868                 log_msg("¤³¤Î¿Í¤Ï¤Þ¤ë¤ÇÅà¤Ã¤Æ¤¤¤ë¤è¤¦¤À¡£");
1869                 goto cleanup;
1870         }
1871
1872         conv = obj->getConversation();
1873         if (!conv) {
1874                 cmdwin_spush("È¿±þ¤¬¤Ê¤¤¡ª");
1875                 log_begin("");
1876                 obj->describe();
1877                 log_end("¤«¤é¤Ï²¿¤ÎÈ¿±þ¤â¤Ê¤«¤Ã¤¿¡£");
1878                 goto cleanup;
1879         }
1880
1881         cmdwin_spush(obj->getName());
1882
1883         if (((obj->getLayer() == being_layer) 
1884              && ((class Character*)obj)->isAsleep())) {
1885                 log_msg("Zzzz...\n");
1886                 goto cleanup;
1887         }
1888
1889         conv_enter(obj, member, conv);
1890         mapSetDirty();
1891
1892  cleanup:
1893         
1894         cmd_cleanup_talk_info(&info);
1895
1896         return;
1897 }
1898
1899 bool cmdZtats(class Character * pc)
1900 {
1901         statusRunApplet(ztats_get_applet()); /* runs until user ESC */
1902         statusSetMode(ShowParty); /* restore default status mode */
1903         return false;
1904 }
1905
1906 static int select_hours(int allow_sunrise)
1907 {
1908         struct get_char_info info;
1909
1910         if (allow_sunrise) {
1911                 cmdwin_spush("<[0-9]»þ´Ö/[s]ÌëÌÀ¤±>");
1912                 info.string = "0123456789sS";
1913         } else {
1914                 cmdwin_spush("<[0-9]»þ´Ö>");
1915                 info.string = "0123456789";
1916         }
1917
1918         info.c = '0';
1919
1920         getkey(&info, &cmd_getchar);
1921
1922         if (! info.c || info.c == '0') {
1923                 cmdwin_pop();
1924                 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1925                 return 0;
1926         }
1927         else if (allow_sunrise
1928                  && (info.c == 's' ||
1929                      info.c == 'S')) {
1930                 int hour;
1931                 int sunrise;
1932
1933                 cmdwin_pop();
1934                 cmdwin_push("ÌëÌÀ¤±¤Þ¤Ç");
1935                 hour = clock_time_of_day() / 60;
1936                 sunrise = SUNRISE_HOUR + 1;
1937                 if (hour < sunrise)
1938                         return sunrise - hour;
1939                 return HOURS_PER_DAY - hour + sunrise;
1940         }
1941         else if (info.c == '1') {
1942                 cmdwin_push("»þ´Ö");
1943                 return 1;
1944         }
1945         else {
1946                 cmdwin_push("»þ´Ö");
1947                 return info.c - '0';
1948         }
1949 }
1950
1951 int ui_get_quantity(int max)
1952 {
1953         struct get_number_info info;
1954         char prompt[64];
1955
1956         /* Push the prompt but remember it for use within getnum() */
1957         if (max == -1) {
1958                 snprintf(prompt, sizeof(prompt), "<¿ôÎÌ>");
1959         } else {
1960                 snprintf(prompt, sizeof(prompt), 
1961                          "<¿ôÎÌ[0-%d]/ENT=%d>", max, max);
1962         }
1963
1964         info.digit = 0;
1965         info.state = GN_ALL;
1966         info.prompt = prompt;
1967
1968         cmdwin_spush(info.prompt);
1969         getkey(&info, getnum);
1970
1971         if (info.state == GN_ALL) {
1972                 if (max == -1)
1973                         info.digit = 0;
1974                 else
1975                         info.digit = max;
1976         } else if (info.state == GN_CANCEL) {
1977                 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1978         }
1979
1980         return info.digit;
1981 }
1982
1983 int cmd_camp_in_wilderness(class Party *camper)
1984 {
1985         int hours, yesno;
1986         class Character *guard = 0;
1987
1988         cmdwin_clear();
1989         cmdwin_spush("µÙ©¤ò¼è¤ë");
1990
1991         if (!place_is_passable(camper->getPlace(), camper->getX(), 
1992                                camper->getY(), camper, PFLAG_IGNOREVEHICLES)) {
1993                 cmdwin_spush("¤³¤³¤Ç¤Ï¤Ç¤­¤Ê¤¤¡ª");
1994                 log_msg("µÙ©¤ò¼è¤ë - ¤³¤³¤Ç¤Ï¤Ç¤­¤Ê¤¤¡ª");
1995                 return 0;
1996         }
1997
1998         if (place_get_subplace(camper->getPlace(), 
1999                                camper->getX(), 
2000                                camper->getY())) {
2001                 cmdwin_spush("¤³¤³¤Ç¤Ï¤Ç¤­¤Ê¤¤¡ª");
2002                 log_msg("µÙ©¤ò¼è¤ë - ¤³¤³¤Ç¤Ï¤Ç¤­¤Ê¤¤¡ª");
2003                 return 0;
2004         }
2005
2006         hours = select_hours(1);
2007         if (hours == 0)
2008                 return 0;
2009
2010         cmdwin_spush(""); /* for the '-' */
2011         cmdwin_spush("¸«Ä¥¤ê¤òÃÖ¤¯");
2012         cmdwin_spush("<y/n>");
2013         getkey(&yesno, &yesnokey);
2014
2015         if (yesno == 'y') {
2016
2017                 cmdwin_pop();
2018                 guard = select_party_member();
2019                 if (!guard) {
2020                         cmdwin_pop();
2021                         cmdwin_push("¸«Ä¥¤ê¤Ê¤·");
2022                 }
2023                 else if (guard->isDead()) {
2024                         log_msg("°äÂΤòΩ¤Æ¤«¤±¡¢Çè¤òʧ¤¤¤Î¤±¤¿¡Ä");
2025                 }
2026                 // else select_party_member() prints the name
2027
2028         } else {
2029                 cmdwin_pop();
2030                 cmdwin_spush("¸«Ä¥¤ê¤Ê¤·");
2031         }
2032
2033         player_party->beginCamping(guard, hours);
2034         camper->endTurn();
2035         run_combat(true, guard, hours, NULL);
2036
2037         return 0;
2038 }
2039
2040 void cmdLoiter(class Being *subject)
2041 {
2042     int hours = 0;
2043
2044         cmdwin_clear();
2045         cmdwin_spush("¤¦¤í¤Ä¤¯");
2046
2047         /* Check if enemies are around. */
2048         if (place_contains_hostiles(subject->getPlace(), subject)) {
2049                 cmdwin_spush("Ũ¤¬¶á¤¯¤Ë¤¤¤ë¡ª");
2050                 log_msg("¤¦¤í¤Ä¤¯ - Å¨¤¬¶á¤¯¤Ë¤¤¤ë¡ª");
2051                 return;
2052         }
2053         
2054         /* Check if any party members are engaged in a task. */
2055         class Character *pc;
2056         if ((pc = cmdAnyPartyMemberEngagedInTask())) {
2057                 log_msg("¤¦¤í¤Ä¤¯ - %s¤ÏÊ̤Τ³¤È¤ò¤·¤Æ¤¤¤ë¡ª", pc->getName());
2058                 cmdwin_spush("Ë»¤·¤¤¡ª");
2059                 return;
2060         }
2061
2062         /* Prompt for the number of hours. */
2063         hours = select_hours(0);
2064         if (!hours) {
2065                 return;
2066         }
2067
2068         /* Tell the party to start loitering. */
2069         cmdwin_spush("¤¦¤í¤Ä¤¤¤Æ¤¤¤ë¡Ä");
2070         player_party->beginLoitering(hours);
2071
2072         /* End the turn. */
2073         subject->endTurn();
2074         
2075 }
2076
2077 int cmd_camp_in_town(class Character *camper)
2078 {
2079         int hours;
2080
2081         cmdwin_clear();
2082         cmdwin_spush("µÙ©¤ò¼è¤ë");
2083
2084         // Party must be in follow mode.
2085         if (player_party->getPartyControlMode() != PARTY_CONTROL_FOLLOW) {
2086                 cmdwin_spush("must be in follow mode!");
2087                 log_begin_group();
2088                 log_msg("µÙ©¤ò¼è¤ë - ÄÉÀ×Ãæ¤Ç¤Ê¤¤¡ª");
2089                 log_msg("¥Ò¥ó¥È: 'f'¤ò²¡¤¹¤ÈÄÉÀפ¹¤ë¡£");
2090                 log_end_group();
2091                 return 0;
2092         }
2093                 
2094         // Check for an object that will serve as a bed.
2095         if (place_get_object(camper->getPlace(), camper->getX(), 
2096                              camper->getY(),  bed_layer) == NULL) {
2097                 cmdwin_spush("¥Ù¥Ã¥É¤¬¤Ê¤¤¡ª");
2098                 log_msg("µÙ©¤ò¼è¤ë - ¥Ù¥Ã¥É¤¬¤Ê¤¤¡ª");
2099                 return 0;
2100         }
2101
2102         // Rendezvous the party around the bed.
2103         if (! player_party->rendezvous(camper->getPlace(), camper->getX(), 
2104                                        camper->getY())) {
2105                 log_msg("µÙ©¤ò¼è¤ë - Ãç´Ö¤È½¸¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2106                 return 0;
2107         }
2108
2109         // Prompt for the number of hours to sleep.
2110         hours = select_hours(! camper->getPlace()->underground);
2111         if (hours == 0)
2112                 return 0;
2113
2114         // Put the party in "sleep" mode before returning back to the main
2115         // event loop.
2116         cmdwin_spush("µÙ©Ãæ¡Ä");
2117         player_party->beginResting(hours);
2118         camper->endTurn();
2119
2120         return TURNS_PER_HOUR;
2121 }
2122
2123 int get_spell_name(struct KeyHandler *kh, int key, int keymod)
2124 {
2125         struct get_spell_name_data *ctx;
2126         char *word, letter;
2127
2128         ctx = (struct get_spell_name_data *) kh->data;
2129
2130         switch (ctx->state) {
2131
2132         case GN_ZERO: /* No spell words are entered yet and the prompt is
2133                        * sitting there. */
2134
2135                 /* Done? */
2136                 if (key == '\n') {
2137                         cmdwin_pop();
2138                         return 1;
2139                 }
2140
2141                 /* Abort? */
2142                 if (key == CANCEL) {
2143                         cmdwin_pop();
2144                         ctx->spell_name[0] = 0;
2145                         return 1;
2146                 }
2147
2148                 /* A letter? */
2149                 if (isalpha(key)) {
2150                         
2151                         /* Lookup the word that goes with the letter. */
2152                         letter = toupper(key);
2153                         word = magic_lookup_word(&Session->magic, letter);
2154
2155                         /* Valid word? */
2156                         if (word) {
2157
2158                                 /* Clear prompt, show the word and advance. */
2159                                 cmdwin_pop();
2160                                 cmdwin_push(word);
2161                                 *ctx->ptr = letter;
2162                                 ctx->ptr++;
2163                                 ctx->n++;
2164                                 ctx->state = GN_SOME;
2165                         }
2166                 }
2167                 return 0;
2168
2169         case GN_SOME: /* One or more words are already entered. */
2170
2171                 /* Done? Ensure null-termination. */
2172                 if (key == '\n') {
2173                         /* Segment-push a null string to force a '-' following
2174                          * the spell name. */
2175                         cmdwin_spush(0);
2176                         *ctx->ptr = 0;
2177                         return 1;
2178                 }
2179
2180                 /* Abort? Terminate string at beginning. */
2181                 if (key == CANCEL) {
2182                         ctx->spell_name[0] = 0;
2183                         return 1;
2184                 }
2185
2186                 /* Backspace? */
2187                 if (key == '\b' && ctx->n) {
2188                         cmdwin_pop();
2189                         ctx->ptr--;
2190                         *ctx->ptr = 0;
2191                         ctx->n--;
2192
2193                         /* Back to empty? Re-prompt. */
2194                         if (!ctx->n) {
2195                                 cmdwin_spush(ctx->prompt);
2196                                 ctx->state = GN_ZERO;
2197                         }
2198                         return 0;
2199                 }
2200
2201                 /* Out of space? */
2202                 if (ctx->n == MAX_WORDS_IN_SPELL_NAME) {
2203                         return 0;
2204                 }
2205
2206                 /* Not a letter? */
2207                 if (!isalpha(key))
2208                         return 0;
2209
2210                 /* Lookup the word that goes with the letter. */
2211                 letter = toupper(key);
2212                 word = magic_lookup_word(&Session->magic, letter);
2213                 if (!word) {
2214                         return 0;
2215                 }
2216                 
2217                 /* Accept the word and print it. After the first word separate words
2218                  * with a space. */
2219                 cmdwin_push(" %s", word);
2220                 *ctx->ptr = letter;
2221                 ctx->ptr++;
2222                 ctx->n++;
2223                 return 0;
2224
2225         default: /* Invalid state */
2226                 assert(0);
2227                 return 0;
2228         }
2229
2230 }
2231
2232 int select_spell(struct get_spell_name_data *context)
2233 {
2234         struct KeyHandler kh;
2235
2236         memset(context, 0, sizeof(*context));
2237         context->ptr = context->spell_name;
2238         context->prompt = "<¼öʸ>";
2239         context->state = GN_ZERO;
2240
2241         kh.fx = get_spell_name;
2242         kh.data = context;
2243
2244         cmdwin_spush(context->prompt);
2245         eventPushKeyHandler(&kh);
2246         eventHandle();
2247         eventPopKeyHandler();
2248
2249         if (strlen(context->spell_name) == 0) {
2250                 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
2251                 return -1;
2252         }
2253
2254         return 0;
2255 }
2256
2257 /**
2258  * Log console messages describing the results of a closure call and return
2259  * whether or not it succeeded.
2260  *
2261  * @param result is what closure_exec() returned. It should be one of the
2262  * standard result codes.
2263  *
2264  * @returns non-zero iff the closure call was successful. "Succesful" means it
2265  * actually did something; whereas "unsuccesful" means the request was
2266  * effectively aborted in the script, so the caller should skip post-processing
2267  * like mp or ap reduction, etc.
2268  */
2269 static int cmd_eval_and_log_result(int result)
2270 {
2271         static struct {
2272                 const char *string;
2273                 int success;
2274         } tbl[] = {
2275                 { "^c+gÀ®¸ù^c-¡ª",              1 },
2276                 { "^c+GÂоݤ¬¤Ê¤¤^c-¡ª",        0 },
2277                 { "^c+y¸ú²Ì¤¬¤Ê¤¤^c-¡ª",        1 },
2278                 { "^c+yŨ¤¬¤¤¤Ê¤¤^c-¡ª",        1 },
2279                 { "^c+GǽÎϤ¬Â­¤ê¤Ê¤¤^c-¡ª",    0 },
2280                 { "^c+r¼ºÇÔ^c-¡ª",              1 },
2281                 { "^c+G¤³¤³¤Ç¤Ï¤Ç¤­¤Ê¤¤^c-¡ª",  0 },
2282                 { "^c+rÃ×̿Ū¤Ê¼ºÇÔ^c-¡ª¡ª¡ª",  1 },
2283                 { "^c+yº£¤Ï¤Ç¤­¤Ê¤¤^c-¡ª",      0 },
2284         };
2285
2286         if (result < 0 || result >= array_sz(tbl)) {
2287                 warn("result code '%d' unknown\n", result);
2288                 return 1;
2289         }
2290
2291         log_continue(tbl[result].string);
2292         return tbl[result].success;
2293 }
2294
2295 bool cmdCastSpell(class Character * pc)
2296 {
2297         struct get_spell_name_data context;
2298         struct inv_entry *ie = NULL;
2299         struct spell *spell;
2300         bool mixed = false;
2301         bool natural = false;
2302         int i, cast = 0, result = 0;
2303         char spell_name[MAX_SPELL_NAME_LENGTH];
2304
2305         if (MagicNegated) {
2306                 log_msg("¾§¤¨¤ë - ÂǤÁ¾Ã¤µ¤ì¤¿¡ª\n");
2307                 return false;
2308         }
2309
2310         cmdwin_clear();
2311         cmdwin_spush("¾§¤¨¤ë");
2312
2313         /* If the pc is null then we are in non-combat mode and need to promp
2314          * the user. */
2315         if (pc == NULL) {
2316                 pc = select_party_member();
2317                 if (pc == NULL) {
2318                         return false;
2319                 }
2320                 statusSetMode(ShowParty);
2321         }
2322
2323         /* Make sure the PC is not asleep, dead, etc. */
2324         if (pc->isDead()) {
2325                 cmdwin_spush("º£¤Ï¤Ç¤­¤Ê¤¤¡ª");
2326                 log_msg("¾§¤¨¤ë - %s¤Ï»à¤ó¤Ç¤¤¤ë¡ª", pc->getName());
2327                 return false;
2328         }
2329
2330         if (pc->isAsleep()) {
2331                 cmdwin_spush("º£¤Ï¤Ç¤­¤Ê¤¤¡ª");
2332                 log_msg("¾§¤¨¤ë - %s¤Ï̲¤Ã¤Æ¤¤¤ë¡ª", pc->getName());
2333                 return false;
2334         }
2335
2336         /* Prompt to select a spell */
2337         if (select_spell(&context) == -1)
2338                 return false;
2339
2340         /* The code for the spell is stored in the context, but not the full
2341          * name. I want the full name for log msgs. */
2342         magic_spell_code_to_name(&Session->magic, spell_name, 
2343                                  MAX_SPELL_NAME_LENGTH, 
2344                                  context.spell_name);
2345
2346         log_begin("%s: %s - ", pc->getName(), spell_name);
2347
2348         /* Lookup the spell in the list of valid spells. */
2349         spell = magic_lookup_spell(&Session->magic, context.spell_name);
2350         if (!spell) {
2351                 /* Bugfix for SF1564255: don't let player guess at spells. */
2352                 cmdwin_spush("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2353                 log_end("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2354                 return false;
2355         }
2356
2357         /* Check if the spell can be used in this context. */
2358         if (!(player_party->getContext() & spell->context)) {
2359                 cmdwin_spush("¤³¤³¤Ç¤Ï»È¤¨¤Ê¤¤¡ª");
2360                 log_end("¤³¤³¤Ç¤Ï»È¤¨¤Ê¤¤¡ª");
2361                 return false;
2362         }
2363
2364         /* Check if the character comes by this spell naturally. */
2365         for (i = 0; i < pc->species->n_spells; i++) {
2366                 if (! strcmp(pc->species->spells[i], spell->code)) {
2367                         natural = true;
2368                         break;
2369                 }
2370         }
2371
2372         /* Check if the caster is of sufficient level. */
2373         /*
2374          * FIXME: what if the spell is natural? cast An Xen Exe on a snake and
2375          * try to cast In Nox Por to see what I mean...
2376          */
2377         if (!natural && pc->getLevel() < spell->level) {
2378                 cmdwin_spush("¤â¤Ã¤È·Ð¸³¤¬É¬Íסª");
2379                 log_end("¥ì¥Ù¥ë%d°Ê¾åɬÍפÀ¡ª", spell->level);
2380                 return false;
2381         }
2382
2383         /* Check party inventory for a mixed spell. */
2384         if (!natural) {
2385                 ie = player_party->inventory->search(spell->type);
2386                 if (ie && ie->count)
2387                         mixed = true;
2388         }
2389
2390         if (!natural && !mixed) {
2391                 cmdwin_spush("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2392                 log_end("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2393                 return false;
2394         }
2395
2396         /* Check if the character has enough mana to cast the spell. */
2397         if (pc->getMana() < spell->cost) {
2398                 cmdwin_spush("¤â¤Ã¤ÈËâÎϤ¬É¬Íסª");
2399                 log_end("¤â¤Ã¤ÈËâÎϤ¬É¬ÍפÀ¡ª");
2400                 return false;
2401         }
2402
2403         /* Cast the spell. */
2404         result = spell->type->cast(pc);
2405         cast = cmd_eval_and_log_result(result);
2406
2407         if (! cast) {
2408                 log_end(NULL);
2409                 return false;
2410         }
2411
2412         /* Decrement the caster's mana. */
2413         pc->runHook(OBJ_HOOK_CAST_DONE, 0);
2414         pc->addMana(0 - spell->cost);
2415         pc->decActionPoints(spell->action_points);
2416         pc->addExperience(spell->cost);
2417
2418         /* If the spell was mixed then remove it from inventory. */
2419         if (mixed) {
2420                 int count = ie->count - 1;
2421                 player_party->takeOut(ie->type, 1);
2422                 if (count) {
2423                         log_msg("¸å%d²ó»Ä¤Ã¤Æ¤¤¤ë¡£", count);
2424                 } else {
2425                         log_msg("¤â¤¦»Ä¤Ã¤Æ¤¤¤Ê¤¤¡£");
2426                 }
2427         }
2428
2429         /* Some spells have status in the foogod window, so repaint it now. */
2430         foogodRepaint();
2431
2432         log_end(NULL);
2433
2434         return true;
2435
2436 }
2437
2438 bool cmdMixReagents(class Character *character)
2439 {
2440         struct spell *spell;
2441         struct get_spell_name_data context;
2442         struct list reagents, *elem;
2443         int quantity, max_quantity;
2444         struct inv_entry *ie, *ie_spell = 0;
2445         bool mistake = false;
2446         char spell_name[MAX_SPELL_NAME_LENGTH];
2447
2448         list_init(&reagents);
2449
2450         cmdwin_clear();
2451         cmdwin_spush("Ä´¹ç¤¹¤ë");
2452
2453         // Select a spell...
2454         if (select_spell(&context) == -1)
2455                 return false;
2456
2457         // The code for the spell is stored in the context, but not the full
2458         // name. I want the full name for log msgs.
2459         magic_spell_code_to_name(&Session->magic, spell_name, 
2460                                  MAX_SPELL_NAME_LENGTH, 
2461                                  context.spell_name);
2462
2463         // Lookup the spell. If null then keep going and bomb when done.
2464         spell = magic_lookup_spell(&Session->magic, context.spell_name);
2465
2466         // Show the player how many he already has mixed...
2467         ie_spell = 0;
2468         if (spell) {
2469                 ie_spell = player_party->inventory->search(spell->type);
2470         }
2471         if (ie_spell && ie_spell->count) {
2472                 cmdwin_spush("%d¤ÄÄ´¹ç¤µ¤ì¤Æ¤¤¤ë", ie_spell->count);
2473         } else {
2474                 cmdwin_spush("Ä´¹ç¤µ¤ì¤Æ¤¤¤Ê¤¤");
2475         }
2476
2477         // Prompt for reagents 
2478         cmdwin_spush("<ÁªÂò¤·¤¿¸å'm'¤ÇÄ´¹ç>");
2479
2480         foogodSetHintText("\005\006=ÁªÂò ENT=²Ã¤¨¤ë/¼è¤ê½ü¤¯ ESC=ÃæÃÇ M=Ä´¹ç");
2481         foogodSetMode(FOOGOD_HINT);
2482
2483         // Show the reagents in the status window
2484         statusSetMode(MixReagents);
2485
2486         struct ScrollerContext sc;
2487         sc.selector = Reagents;
2488         sc.done = false;
2489         sc.abort = false;
2490         sc.mixing = true;
2491
2492         struct KeyHandler kh;
2493         kh.fx = scroller;
2494         kh.data = &sc;
2495
2496         eventPushKeyHandler(&kh);
2497
2498         for (;;) {
2499                 sc.selection = NULL;
2500                 eventHandle();
2501
2502                 if (sc.abort) {
2503                         // u5 silently aborts here
2504                         cmdwin_pop();
2505                         eventPopKeyHandler();
2506                         cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
2507                         goto done;
2508                 }
2509
2510                 if (sc.done)
2511                         break;
2512
2513                 ie = (struct inv_entry *) sc.selection;
2514                 if (! ie) {
2515                         /* This happens when the player has no reagents
2516                          * whatsoever. */
2517                         cmdwin_pop();
2518                         eventPopKeyHandler();
2519                         cmdwin_spush("¤Ê¤Ë¤â¤·¤Ê¤¤¡ª");
2520                         goto done;
2521                 }
2522
2523                 if (ie->ref) {
2524                         // unselect
2525                         ie->ref = 0;
2526                         list_remove(&ie->auxlist);
2527                 } else {
2528                         // select
2529                         ie->ref = 1;
2530                         list_add(&reagents, &ie->auxlist);
2531                 }
2532
2533                 statusRepaint();
2534         }
2535
2536         cmdwin_pop();
2537         eventPopKeyHandler();
2538
2539         if (list_empty(&reagents)) {
2540                 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
2541                 goto done;
2542         }
2543
2544         // Determine the max number of mixtures the player can make.
2545         max_quantity = 0x7fffff;
2546         list_for_each(&reagents, elem) {
2547                 ie = outcast(elem, struct inv_entry, auxlist);
2548                 if (ie->count < max_quantity) {
2549                         max_quantity = ie->count;
2550                 }
2551         }
2552
2553         // Prompt for the number of mixtures to make
2554         for (;;) {
2555
2556                 int dummy;
2557
2558                 cmdwin_push_mark();
2559                 quantity = ui_get_quantity(max_quantity);
2560
2561                 if (quantity == 0) {
2562                         goto done;
2563                 }
2564
2565                 if (quantity <= max_quantity)
2566                         break;
2567
2568                 cmdwin_spush(0); /* for the '-' after the quantity */
2569                 cmdwin_spush("ÈëÌô¤¬Â­¤ê¤Ê¤¤¡ª");
2570                 getkey(&dummy, anykey);
2571                 cmdwin_pop_to_mark();
2572         }
2573
2574         cmdwin_push("-");
2575         log_begin("Ä´¹ç¤¹¤ë: %s - ", spell_name);
2576
2577         // For each reagent required by the spell, check if it is in the list
2578         // of reagents given by the player. If not then remember this fact. If
2579         // the reagent is found then remove it from player inventory and remove
2580         // it from the list.
2581         if (spell) {
2582                 for (int i = 0; i < spell->n_reagents; i++) {
2583                         bool found = false;
2584                         list_for_each(&reagents, elem) {
2585                                 ie = outcast(elem, struct inv_entry, auxlist);
2586                                 if (ie->type ==
2587                                     (class ObjectType *) spell->reagents[i]) {
2588                                         // The following line is safe only
2589                                         // because this is the end of the
2590                                         // list_for_each loop!
2591                                         list_remove(elem);
2592                                         ie->ref--;
2593                                         player_party->takeOut(ie->type, 
2594                                                               quantity);
2595                                         found = true;
2596                                         break;
2597                                 }
2598                         }
2599                         if (!found)
2600                                 mistake = true;
2601                 }
2602         }
2603
2604         // Now, if any reagents remain leftover then remember this fact and
2605         // remove the remaining reagents from inventory.
2606         if (!list_empty(&reagents)) {
2607                 mistake = true;
2608                 elem = reagents.next;
2609                 while (elem != &reagents) {
2610                         struct list *tmp = elem->next;
2611                         ie = outcast(elem, struct inv_entry, auxlist);
2612                         list_remove(elem);
2613                         elem = tmp;
2614                         ie->ref--;
2615                         player_party->takeOut(ie->type, quantity);
2616                 }
2617         }
2618
2619         statusSetMode(ShowParty);
2620         foogodSetMode(FOOGOD_DEFAULT);
2621
2622         // committed to action now, so decrement AP
2623         if (character) {
2624                 character->runHook(OBJ_HOOK_MIX_DONE, 0);
2625                 
2626                 if (!spell)
2627                 {
2628                     // Failed attempt (mixing a spell which does not exist)
2629                     int num  = kern_intvar_get("AP_COST:mix_reagents_nospell_num");
2630                     int dice = kern_intvar_get("AP_COST:mix_reagents_nospell_dice");
2631                     int plus = kern_intvar_get("AP_COST:mix_reagents_nospell_plus");
2632                     int AP_wasted = dice_roll_numeric(num, dice, plus);
2633                     character->decActionPoints(AP_wasted);
2634                     // was 3d50+20 -- dice_roll_numeric(3, 50, 20)
2635                 }
2636                 else if (mistake)
2637                 {
2638                     int level = spell->level;
2639                     int num  = kern_intvar_get("AP_COST:mix_reagents_badmix_num");
2640                     int dice = kern_intvar_get("AP_COST:mix_reagents_badmix_dice");
2641                     int plus = kern_intvar_get("AP_COST:mix_reagents_badmix_plus");
2642                     int AP_wasted = dice_roll_numeric(level * num, dice, plus);
2643                     character->decActionPoints(AP_wasted);
2644                     // was 1d(2*AP)+100 -- dice_roll_numeric(1 ,(2 * spell->action_points) , 100)
2645                  }
2646                 else
2647                 {
2648                     // mixing should be SLOW
2649                     int base      = kern_intvar_get("AP_COST:mix_reagents_base");
2650                     int per_mix   = kern_intvar_get("AP_COST:mix_reagents_per_mix");
2651                     int per_level = kern_intvar_get("AP_COST:mix_reagents_per_level");
2652                     int AP_spent  = base + (quantity * per_mix) + (spell->level * per_level);
2653                     character->decActionPoints(AP_spent);
2654                     // was 100 + 2 * spell->action_points
2655                 }
2656         }
2657
2658         // If the spell is invalid or the reagents are incorrect then punish
2659         // the player.
2660         if (!spell) {
2661                 cmdwin_spush("¤ª¤ª¤Ã¤È¡ª");
2662                 player_party->damage(DAMAGE_ACID);
2663                 log_end("»À¤À¡ª");
2664                 goto done;
2665
2666         } else if (mistake) {
2667                 cmdwin_spush("¤¦¤ï¤¢¤Ã¡ª");
2668                 player_party->damage(DAMAGE_BOMB);
2669                 log_end("Çúȯ¡ª");
2670                 goto done;
2671         }
2672
2673         // All is well. Add the spell to player inventory.
2674         cmdwin_spush("À®¸ù");
2675         player_party->add(spell->type, quantity);
2676         log_end("À®¸ù¡ª");
2677
2678  done:
2679         // In case of cancellation I need to unselect all the reagents.
2680         elem = reagents.next;
2681         while (elem != &reagents) {
2682                 struct list *tmp = elem->next;
2683                 ie = outcast(elem, struct inv_entry, auxlist);
2684                 list_remove(elem);
2685                 elem = tmp;
2686                 ie->ref--;
2687         }
2688         statusSetMode(ShowParty);
2689         foogodSetMode(FOOGOD_DEFAULT);
2690         return true;
2691 }
2692
2693 void look_at_XY(struct place *place, int x, int y, void *unused)
2694 {
2695         if (DeveloperMode) {
2696                 log_begin("At XY=(%d,%d): ", x, y);
2697         } else {
2698                 log_begin("");
2699         }
2700
2701         if ( mapTileIsVisible(x, y) ) {
2702                 if (mapTileLightLevel(x,y) < MIN_XAMINE_LIGHT_LEVEL) {
2703                         log_continue("°Å¤¹¤®¤ë¡ª");
2704                 } else {
2705                         place_describe(place, x, y, PLACE_DESCRIBE_ALL);
2706                         log_continue("¤¬¸«¤¨¤ë¡£");
2707                 }
2708         } else if (ShowAllTerrain || XrayVision) {
2709                 place_describe(place, x, y, PLACE_DESCRIBE_TERRAIN);
2710                 log_continue("¤¬Æ©»ë¤Ç¤­¤ë¡£");
2711         } else {
2712                 log_continue("¸«¤¨¤Ê¤¤¡ª");
2713         }
2714
2715         log_end(NULL);
2716 }
2717
2718 int detailed_examine_XY(struct place *place, int x, int y, void *unused)
2719 {
2720         if (DeveloperMode) {
2721                 log_begin("At XY=(%d,%d): ", x, y);
2722         } else {
2723                 log_begin("");
2724         }
2725
2726         if ( mapTileIsVisible(x, y) ) {
2727                 if (mapTileLightLevel(x,y) < MIN_XAMINE_LIGHT_LEVEL) {
2728                         log_continue("¸«¤¨¤Ê¤¤¡ª");
2729                 } else {
2730                         log_continue("¼¡¤Î¤â¤Î¤¬¸«¤¨¤ë¡£\n");
2731                         place_examine(place, x, y);
2732                 }
2733         } else if (ShowAllTerrain || XrayVision) {
2734                 log_continue("¼¡¤Î¤â¤Î¤¬Æ©»ë¤Ç¸«¤¨¤ë¡£\n");
2735                 place_examine(place, x, y);
2736         } else {
2737                 log_continue("¸«¤¨¤Ê¤¤¡ª");
2738         }
2739
2740         #if 0
2741         // SAM: 
2742         // Hmmm...how best to print more info about
2743         // the objects on this tile?
2744         if ( mapTileIsVisible(x, y) ) {
2745                 log_msg("DETAIL XY=(%d,%d) TODO - print detailed view\n", x, y);
2746                 // For each object/terrain on the tile, print the name (and
2747                 // perhaps show the sprite in a Status Window mode), and also
2748                 // show:
2749                 //
2750                 //     o whether this object blocks LOS (alpha)
2751                 //     o whether this object blocks movement (pmask)
2752                 //     o whether this object causes some effect when stepped
2753                 //       upon (hazardous terrain effects, pressure plate
2754                 //       triggers)
2755                 //     o information specific to the object type, such as:
2756                 //     o Triggers: current state, and perhaps what it is 
2757                 //       connected to?
2758                 //     o NpcParties: faction, movement mode 
2759                 //       (pmask), ...
2760                 //     o Vehicles: movement mode, armament, current HP
2761                 //     o Portable items: weapon/armor stats, (U)se effects, 
2762                 //       etc...
2763                 // Hmmm...what else?
2764                 return;
2765         }
2766         log_msg("DETAIL XY=(%d,%d) out of LOS\n", x, y);
2767         #endif
2768         
2769         log_end(NULL);
2770
2771         return 0; /* keep on targeting */
2772 }
2773
2774 bool cmdXamine(class Object * pc)
2775 {
2776         // SAM: Working on an improved (L)ook command,
2777         // which works as a "Look Mode" rather than a 
2778         // "look at 1 tile" command...
2779         int x, y;
2780         bool ret = true;
2781
2782         cmdwin_clear();
2783         cmdwin_spush("Ä´¤Ù¤ë");
2784
2785         x = pc->getX();
2786         y = pc->getY();
2787
2788         log_begin_group();
2789
2790         if (pc)
2791                 log_msg("%s¤Ï¤¢¤¿¤ê¤òÄ´¤Ù¤¿¡Ä", pc->getName());
2792         else
2793                 log_msg("¤¢¤Ê¤¿¤Ï¤¢¤¿¤ê¤òÄ´¤Ù¤¿¡Ä");
2794
2795         look_at_XY(pc->getPlace(), x, y, 0);  // First look at the current tile
2796         if (select_target_with_doing(x, y, &x, &y, pc->getVisionRadius(),
2797                                      look_at_XY, detailed_examine_XY) == -1) {
2798                 ret = false;
2799         }
2800
2801         log_end_group();
2802
2803         return ret;
2804 } // cmdXamine()
2805
2806 const char * name_of_context (void)
2807 {
2808         // SAM: Perhaps this function belongs in common.c?
2809         switch (player_party->getContext()) {
2810         case CONTEXT_WILDERNESS:
2811                 return "Á´°÷¤Î¾õÂÖ";
2812                 break;
2813         default:
2814                 return "¸Ä¿Í¤Î¾õÂÖ";
2815                 break;
2816         }
2817 } // name_of_context()
2818
2819 bool cmdAT (class Character * pc)
2820 {
2821         int x, y;
2822         const char * who = "";
2823         const char * place_name = "";
2824
2825         cmdwin_clear();
2826
2827         // Should I check player_party->context
2828         // for the context info below, 
2829         // rather than the current method?
2830         if (pc) {
2831                 // A party member was specified as a parameter, so this must be
2832                 // combat mode. Use the party member's location as the origin.
2833                 who = pc->getName();
2834                 place_name =  Place->name;
2835                 x = pc->getX();
2836                 y = pc->getY();
2837         }
2838         else {
2839                 // Must be party mode. 
2840                 // Use the player party's location as the origin.
2841                 who = "Á´°÷";
2842                 place_name = player_party->getPlace()->name;
2843                 x = player_party->getX();
2844                 y = player_party->getY();
2845         }
2846         // SAM: Why is this line not safe in combat mode?
2847         //      Would it be The Right Thing (TM) 
2848         //      for it to be made safe in all contexts?
2849         // place_name = player_party->getPlace()->name;
2850     
2851         log_begin_group();
2852         log_msg("¤³¤ì¤Ï%s¤Ç¤¢¤ë¡£", name_of_context() );
2853         log_msg("%s¤Ï%s¤Ë¤¤¤ë¡£", who, place_name);
2854         if (Place->underground) {
2855                 log_msg("º£¤Ï%dǯ %s %s %s¤À¡£", 
2856                 Session->clock.year, month_name(), week_name(), day_name() );
2857         } else {
2858                 log_msg("º£¤Ï%dǯ %s %s "
2859                 "%s¤Î%s¤À¡£",
2860                 Session->clock.year, month_name(), week_name(), 
2861                 day_name(), vague_time_as_string() );
2862         }
2863         // SAM: Is this really interesting though, I wonder?
2864         log_msg("%d²ó¤¬·Ð²á¤·¤¿¡£", Turn);
2865
2866         log_msg("É÷¤Ï%s¤«¤é¿á¤¤¤Æ¤¤¤ë¡£",
2867                 directionToString(windGetDirection()) );
2868
2869         if (Place->underground) {
2870                 log_msg("%s¤ÏÃϲ¼¤Ë¤¤¤Æ¶õ¤Ï¸«¤¨¤Ê¤¤¡£", 
2871                         who);
2872         } // underground
2873         else {
2874                 struct list *elem;
2875                 
2876                 // SAM: 
2877                 // This message won't be true if you are under 
2878                 // a roof in a town.  In future there should be 
2879                 // logic querying the (future) roof-ripping code here.
2880                 log_msg("%s¤Ï¶õ¤Î¸«¤¨¤ë¾ì½ê¤Ë¤¤¤ë¡£", who);
2881
2882                 // The kernel no longer has any special knowledge about which
2883                 // astral body is the sun, so we have to deal with all astral
2884                 // bodies generically now. I mean, a game may have two or even
2885                 // more suns. The time runs independently and isn't cued off
2886                 // the sun.
2887                 if (is_noon()) {
2888                         log_msg("Æü¤¬¾º¤Ã¤Æ¤¤¤ë¡£");
2889                 } else if (is_midnight()) {
2890                         log_msg("Æü¤ÏÄÀ¤ó¤Ç¤¤¤ë¡£");
2891                 }
2892
2893                 // Report on each astral body generically.
2894                 list_for_each(&Session->sky.bodies, elem) {
2895                         struct astral_body *body;
2896                         body = outcast(elem, struct astral_body, list);
2897                         if (astral_body_is_visible(body->arc)) {
2898                                 log_begin("%s¤Î¹â¤µ¤Ï%dÅÙ", body->name, 
2899                                         body->arc);
2900                                 if (body->n_phases > 1) {
2901                                         char *phase_name = 
2902                                                 body->phases[body->phase].
2903                                                 name;
2904                                         if (phase_name) {
2905                                                 log_continue("¡¢%s",
2906                                                              phase_name);
2907                                         } else {
2908                                                 log_continue("¡¢·îÁê¤Ï%d", 
2909                                                              body->phase);
2910                                         }
2911                                 }
2912                                 log_end("¤À¡£");
2913                         }
2914                 }
2915
2916         } // open air, under the sky
2917
2918         if (player_party->getVehicle()) {
2919                 log_msg("%s¤Ï%s¤Ë¾è¤Ã¤Æ¤¤¤ë¡£", 
2920                         who, player_party->getVehicle()->getName() );
2921                 // SAM:
2922                 // In future, we shall want GhulScript to specify 
2923                 // whether one is to be
2924                 //     "riding" "driving" "piloting" "sailing"
2925                 // a particular vehicle type.
2926                 // The existing 'mv_desc' field (Ride, Sail)
2927                 // is related, but we need the gerund of the verb.
2928         }
2929         else {
2930                 // SAM: Not true for a party of Gazers or Nixies.
2931                 // Similar GhulScript for party / character movement mode
2932                 // descriptions and gerunds?
2933                 log_msg("%s¤ÏÊ⤤¤Æ¤¤¤ë¡£", who);
2934         }
2935
2936         log_end_group();
2937
2938         /*
2939           Information reported shall include:
2940           X the current place,X,Y
2941           X the in-game time in game time units (HH:MM, YYYY/MM/DD)
2942           X the in-game time in elapased turns (this is of less interest)
2943           X the current weather status (wind)
2944           X the current astronomy (day/night, sun, moons)
2945           X the UI mode of the party (Wilderness,Town,Dungeon,Combat)
2946           X whether the party is on foot or in a vehicle (and what type)
2947           . the number of party members, names, order, and basic vital stats
2948           . global party stats such as food and gold
2949           . any special effects (buffs/nerfs) currently affecting the party,
2950           . such as haste/quickness/slow, time stop, protection, etc.
2951           . Xamine type information about the tile the party is standing on.
2952         */
2953
2954         return true;
2955 } // cmdAT()
2956
2957 /**
2958  * cmd_terraform - edit terrain interactively
2959  */
2960 bool cmd_terraform(struct place *place, int x, int y)
2961 {
2962     terrain_editor_run(place, x, y);
2963     return true;
2964 }
2965
2966 bool cmd_save_current_place (struct place * place)
2967 {
2968     FILE *   file;
2969     const char *   file_path;
2970     save_t * save;
2971     int ret;
2972
2973     //log_msg("cmd_save_current_place");
2974     //printf("cmd_save_current_place()\n");
2975
2976     file_path = "_test_save_place";
2977
2978     file = file_open_in_save_dir(file_path, "w");
2979     if (file == NULL) {
2980         log_msg("Save place to file '%s' failed.", file_path);
2981         printf("Error on fopen() for file '%s': '%s'\n", file_path, strerror(errno));
2982         return 0;
2983     }
2984     Session->session_id++;  // Must increment to cause saving.
2985
2986     save = save_new(file);
2987     save->indent     = 0;
2988     save->session_id = Session->session_id;
2989
2990     //terrain_map_print(file, 0, place->terrain_map);
2991     terrain_map_save(save, place->terrain_map);
2992     log_msg("Saved map to file:\n'%s'", file_path);
2993     printf( "Saved map to file '%s'\n", file_path);
2994
2995     save_del(save);
2996
2997     ret = fclose(file);
2998     if (ret != 0) {
2999         // SAM: Not sure what we can do about it, 
3000         //      and this seems kind of low-level to log_msg() about...
3001         printf("Error on fclose() for file '%s': '%s'\n", file_path, strerror(errno));
3002         // It seems that the save method should return non-void, 
3003         // so that we know success/failure in this and other cases...
3004         return 0;
3005     }
3006     return 1;
3007 }
3008
3009 void cmdZoomIn(void)
3010 {
3011         struct place *subplace = 0;
3012         // 
3013         // SAM: Curently no "Enter" message is printed.  It turns out to be
3014         // moderately complicated to do so properly, as a distinct message for
3015         // each enter_combat() case might be desired...
3016         // 
3017         // For now, I print a placeholder message for each case here:
3018         
3019         if ((subplace = place_get_subplace(player_party->getPlace(),
3020                                                   player_party->getX(),
3021                                                   player_party->getY()))) {
3022                 if (ENABLE_TOWN_ZOOM_IN) {
3023                         // Standing over a subplace. Try to enter with no
3024                         // direction, this will prompt the player to provide a
3025                         // direction.
3026                         log_msg("Æþ¤ë-%s", subplace->name);
3027                         player_party->try_to_enter_subplace_from_edge(subplace,
3028                                                                       0, 0);
3029                 } else {
3030                         log_msg("Æþ¤ë-Æþ¤ê¸ý¤«¤éÆþ¤Ã¤¿¡ª");
3031                 }
3032
3033         } else if (!place_is_passable(player_party->getPlace(),
3034                                       player_party->getX(),
3035                                       player_party->getY(),
3036                                       player_party,
3037                                       PFLAG_IGNOREVEHICLES)) {
3038
3039                 // Currently zooming in to impassable terrain is not doable;
3040                 // since the party might not be placeable on the default map,
3041                 // which would be a solid grid of that impassable terrain.
3042                 // Also, if somehow placed, the party could not escape unless
3043                 // on an edge.  There would be no harm in it otherwise,
3044                 // however.
3045                 struct terrain * tt = 
3046                         place_get_terrain(player_party->getPlace(),
3047                                           player_party->getX(),
3048                                           player_party->getY() );
3049                 log_msg("Æþ¤ë-%s¤Ë¤ÏÆþ¤ì¤Ê¤¤¡ª", tt->name);
3050         } else {
3051                 // If standing on ordinary terrain, zoom in:
3052                 struct terrain * tt = 
3053                         place_get_terrain(player_party->getPlace(),
3054                                           player_party->getX(),
3055                                           player_party->getY() );
3056                 log_msg("Æþ¤ë-%s", tt->name);
3057                 run_combat(false, 0, 0, NULL);
3058         }
3059 }
3060
3061 bool cmdSave(void)
3062 {
3063     bool ret = true;
3064     class Character *pc;
3065     if ((pc = cmdAnyPartyMemberEngagedInTask())) {
3066         log_msg("µñÈÝ - %s¤ÏÊ̤Τ³¤È¤ò¤·¤Æ¤¤¤ë¡ª", pc->getName());
3067         cmdwin_spush("busy with tasks!");
3068         return false;
3069     }
3070
3071     char *fname = save_game_menu();
3072     if (!fname) {
3073         cmdwin_spush("Ãæ»ß¡ª");
3074         return false;
3075     }
3076     
3077     log_begin("%s¤ËÊݸÃæ¡Ä", fname);
3078     if (session_save(fname)) {
3079         log_end("^c+r¼ºÇÔ¡ª^c-");
3080         cmdwin_spush("¼ºÇÔ¡ª");
3081         ret = false;
3082     } else {
3083         cmdwin_spush("ok!");
3084         log_end("^c+g´°Î»¡ª^c-");
3085     }
3086     session_save(fname);
3087     free(fname);
3088     return ret;
3089 }
3090
3091 void cmdReload(void)
3092 {
3093         Reload = 1;        
3094 }
3095
3096 /****** New UI ******/
3097
3098 #define MARKUP 4
3099
3100
3101 int ui_get_yes_no(const char *name)
3102 {
3103         int yesno;
3104         cmdwin_clear();
3105         cmdwin_spush("ÊÖÅú");
3106         cmdwin_spush("<y/n>");
3107         getkey(&yesno, yesnokey);
3108         cmdwin_pop();
3109         if (yesno == 'y') {
3110                 cmdwin_spush("¤Ï¤¤");
3111                 log_msg("^c+%c%s:^c- ¤Ï¤¤", CONV_PC_COLOR, name);
3112                 return 1;
3113         } else {
3114                 cmdwin_spush("¤¤¤¤¤¨");
3115                 log_msg("^c+%c%s:^c- ¤¤¤¤¤¨", CONV_PC_COLOR, name);
3116                 return 0;
3117         }
3118 }
3119
3120 typedef struct ui_getline_data {
3121         char *ptr;
3122         char *buf;
3123         int room;
3124         int (*filter)(int key);
3125 } getline_t;
3126
3127 static int ui_getline_handler(struct KeyHandler *kh, int key, int keymod)
3128 {
3129         getline_t *data = (getline_t*)kh->data;
3130         char kana_buf[128];
3131         int kana_len;
3132         int i;
3133
3134         if (key == CANCEL) {
3135                 while (data->ptr > data->buf) {
3136                         data->ptr--;
3137                         *data->ptr = 0;
3138                         cmdwin_pop();
3139                         data->room++;
3140                 }
3141                 alpha_to_kana(0, NULL);
3142                 return 1;
3143         }
3144
3145         if (key == '\n') {
3146                 alpha_to_kana(0, NULL);
3147                 return 1;
3148         }
3149
3150         if (key == '\b') {
3151                 if (data->ptr != data->buf) {
3152                         if (*(data->ptr - 1) & 0x80) {
3153                                 data->ptr -= 2;
3154                                 *data->ptr = 0;
3155                                 data->room += 2;
3156                                 cmdwin_pop();
3157                                 cmdwin_pop();
3158                         } else {
3159                                 data->ptr--;
3160                                 *data->ptr = 0;
3161                                 data->room++;
3162                                 cmdwin_pop();
3163                         }
3164                 }
3165                 alpha_to_kana(0, NULL);
3166                 return 0;
3167         }
3168
3169         if (data->filter
3170             && data->filter(key)) {
3171                 alpha_to_kana(0, NULL);
3172                 return 0;
3173         }
3174
3175         if ((isprintable(key) || (key & 0x80))
3176             && data->room) {
3177                 cmdwin_push("%c", key);
3178                 *data->ptr++ = key;
3179                 data->room--;
3180         }
3181
3182         kana_len = alpha_to_kana (key, kana_buf);
3183         if (kana_len) {
3184                 for (i = 0; i < kana_len; i++) {
3185                         ui_getline_handler (kh, kana_buf[i], keymod);
3186                 }
3187         }
3188
3189         return 0;
3190 }
3191
3192 int ui_getline_filtered(char *buf, int len, int (*filter)(int key))
3193 {
3194         struct KeyHandler kh;
3195         getline_t data;
3196
3197         data.buf  = buf;
3198         data.ptr  = buf;
3199         data.room = len - 1;
3200         data.filter = filter;
3201
3202         memset(buf, 0, len);
3203
3204         kh.fx   = ui_getline_handler;
3205         kh.data = &data;
3206
3207         eventPushKeyHandler(&kh);
3208         eventHandle();
3209         eventPopKeyHandler();
3210
3211         return len - (data.room + 1);        
3212 }
3213
3214 int ui_getline_plain(char *buf, int len)
3215 {
3216         return ui_getline_filtered(buf, len, 0);
3217 }
3218
3219 int ui_getline(char *buf, int len)
3220 {
3221         cmdwin_clear();
3222         cmdwin_push("¸À¤¦: ");
3223         return ui_getline_plain(buf, len);
3224 }
3225
3226 int ui_buy(struct merchant *merch)
3227 {
3228         struct KeyHandler kh;
3229         struct ScrollerContext sc;
3230         struct trade_info *trade;
3231         int quantity, cost, max_q, bought = 0;
3232
3233         statusSetTradeInfo(merch->n_trades, merch->trades);
3234         statusSetMode(Trade);
3235
3236         sc.selector = TradeItem;
3237         kh.fx = scroller;
3238         kh.data = &sc;
3239
3240         for (;;) {
3241
3242                 // *** selection ***
3243
3244                 sc.selection = NULL;
3245
3246                 cmdwin_clear();
3247                 cmdwin_spush("Ç㤦");
3248                 cmdwin_spush("<ÁªÂò/ESC>");
3249                 eventPushKeyHandler(&kh);
3250                 eventHandle();
3251                 eventPopKeyHandler();
3252                 cmdwin_pop();
3253
3254                 trade = (struct trade_info *) sc.selection;
3255
3256                 if (!trade) {
3257                         cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3258                         break;
3259                 }
3260
3261                 /* Print the sales pitch to the console, if one exists */
3262                 if (trade->sales_pitch) {
3263                         log_msg("^c+%c%s:^c- %s", CONV_NPC_COLOR, merch->name,
3264                                 trade->sales_pitch);
3265                 }
3266
3267                 cmdwin_spush("%s", trade->name);
3268
3269                 if (player_party->gold < trade->cost) {
3270                         int dummy;
3271                         cmdwin_spush("¶â²ß¤¬Â­¤ê¤Ê¤¤¡ª <¥­¡¼¤ò²¡¤¹>");
3272                         getkey(&dummy, anykey);
3273                         continue;
3274                 }
3275                 // *** quantity ***
3276
3277                 cmdwin_push_mark();
3278                 max_q = player_party->gold / trade->cost;
3279                 quantity = ui_get_quantity(max_q);
3280                 cmdwin_pop_to_mark();
3281
3282                 if (quantity == 0) {
3283                         cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3284                         continue;
3285                 }
3286
3287                 quantity = min(quantity, max_q);
3288                 cmdwin_spush("%d", quantity);
3289
3290                 cost = quantity * trade->cost;
3291
3292                 // *** trade ***
3293
3294                 class ObjectType *type = (class ObjectType*)trade->data;
3295                 cmdwin_spush("Çã¤Ã¤¿");
3296                 log_msg("¤¢¤Ê¤¿¤Ï%s¤ò¶â²ß%dËç¤Ç%d¤ÄÇã¤Ã¤¿¡£\n", trade->name, 
3297                              cost, quantity);
3298
3299                 player_party->gold -= cost;
3300                 if (type->canBuy()) {
3301                         type->buy(player_party->get_leader(), quantity);
3302                 } else {
3303                         player_party->add(type, quantity);
3304                 }
3305                 trade->quantity = player_party->inventory->numAvail(type);
3306                 statusRepaint();
3307                 foogodRepaint();
3308                 bought++;
3309         }
3310
3311         statusSetMode(ShowParty);
3312         return bought;
3313 }
3314
3315 static bool conv_filter_trade(struct inv_entry *ie, void *fdata)
3316 {
3317         struct trade_info *trade = (struct trade_info*)fdata;
3318         return (ie->type == trade->data && ie->count > ie->ref);
3319 }
3320
3321 static int fill_sell_list(struct merchant *merch, struct trade_info *trades)
3322 {
3323         struct inv_entry *ie = NULL;
3324         struct filter filter;
3325         int i, j = 0;
3326
3327         filter.fx = conv_filter_trade;
3328
3329         for (i = 0; i < merch->n_trades; i++) {
3330
3331                 if (merch->trades[i].cost / MARKUP == 0)
3332                         continue;
3333                 
3334                 filter.fdata = &merch->trades[i];
3335                 ie = player_party->inventory->first(&filter);
3336                 if (!ie)
3337                         continue;
3338
3339                 /* Why don't aren't we setting show_sprite here, too? */
3340                 trades[j] = merch->trades[i];
3341                 trades[j].cost /= MARKUP;
3342                 trades[j].quantity = ie->count - ie->ref;
3343                 trades[j].show_quantity = 1;
3344                 j++;
3345         }
3346
3347         return j;
3348 }
3349
3350 int ui_sell(struct merchant *merch)
3351 {
3352         // A bit trickier than the "Buy" scenario. A merchant will only buy
3353         // items that it is willing to turn around and sell at a profit. When
3354         // it comes time to select an item to sell the user should only see the
3355         // list of items in player inventory which the merchant is willing to
3356         // buy. So here we need to build that list and feed it to the status
3357         // viewer.
3358
3359         int n_trades = 0;
3360         struct trade_info *trades;
3361         struct KeyHandler kh;
3362         struct ScrollerContext sc;
3363         struct trade_info *trade;
3364         int sold = 0;
3365
3366         // Allocate the trade list.
3367         trades = new struct trade_info[merch->n_trades];
3368         if (!trades) {
3369                 log_msg("^c+%c%s:^c- ¤½¤ì¤Ï¤¤¤é¤Ê¤¤¡£\n", 
3370                         CONV_NPC_COLOR, merch->name);                
3371                 return 0;
3372         }
3373         // Fill out the list
3374         n_trades = fill_sell_list(merch, trades);
3375         statusSetTradeInfo(n_trades, trades);
3376         statusSetMode(Trade);
3377
3378         sc.selector = TradeItem;
3379         kh.fx = scroller;
3380         kh.data = &sc;
3381
3382         for (;;) {
3383
3384                 struct inv_entry *ie;
3385                 int quantity, max_q;
3386
3387                 sc.selection = NULL;
3388
3389                 cmdwin_clear();
3390                 cmdwin_spush("Çä¤ë");
3391                 cmdwin_spush("<ÁªÂò/ESC>");
3392                 eventPushKeyHandler(&kh);
3393                 eventHandle();
3394                 eventPopKeyHandler();
3395                 cmdwin_pop();
3396
3397                 trade = (struct trade_info *) sc.selection;
3398
3399                 if (!trade) {
3400                         cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3401                         break;
3402                 }
3403
3404                 cmdwin_spush("%s", trade->name);
3405
3406                 ie = player_party->inventory->search((class ObjectType *) 
3407                                                      trade->data);
3408                 assert(ie);
3409                 assert(ie->ref < ie->count);
3410
3411                 // quantity
3412
3413                 max_q = ie->count - ie->ref;
3414
3415                 cmdwin_push_mark();
3416                 quantity = ui_get_quantity(max_q);
3417                 cmdwin_pop_to_mark();
3418
3419                 if (quantity == 0) {
3420                         cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3421                         continue;
3422                 }
3423
3424                 quantity = min(quantity, max_q);
3425                 cmdwin_spush("%d", quantity);
3426
3427                 // make the trade
3428                 player_party->takeOut(ie->type, quantity);
3429                 player_party->gold += quantity * trade->cost;
3430                 foogodRepaint();
3431
3432                 cmdwin_spush("ok");
3433                 log_msg("¤¢¤Ê¤¿¤Ï%s¤ò¶â²ß%dËç¤Ç%d¤ÄÇä¤Ã¤¿¡£\n", trade->name,
3434                              quantity * trade->cost, quantity);
3435
3436                 // refresh the sell list
3437                 n_trades = fill_sell_list(merch, trades);
3438                 statusSetTradeInfo(n_trades, trades);
3439                 statusUpdateTradeInfo(n_trades, trades);
3440                 sold++;
3441         }
3442
3443         statusSetMode(ShowParty);
3444
3445         delete trades;
3446         return sold;
3447 }
3448
3449 static int get_buy_or_sell_key(struct KeyHandler *kh, int key, int keymod)
3450 {
3451         int *val = (int *) kh->data;
3452
3453         switch (key) {
3454         case 'b':
3455         case 'B':
3456                 *val = 'b';
3457                 return 1;
3458         case 's':
3459         case 'S':
3460                 *val = 's';
3461                 return 1;
3462         case CANCEL:
3463                 *val = 'x';
3464                 return 1;
3465         default:
3466                 return 0;
3467         }
3468 }
3469
3470 int ui_trade(struct merchant *merch)
3471 {
3472         int key, traded = 0;
3473
3474         for (;;) {
3475                 cmdwin_clear();
3476                 cmdwin_spush("Ç㤦/Çä¤ë¡©");
3477                 cmdwin_spush("<B:Ç㤦/S:Çä¤ë/ESC>");
3478                 getkey(&key, get_buy_or_sell_key);
3479
3480                 switch (key) {
3481                 case 'b':
3482                         traded += ui_buy(merch);
3483                         break;
3484                 case 's':
3485                         traded += ui_sell(merch);
3486                         break;
3487                 default:
3488                         cmdwin_pop();
3489                         cmdwin_spush("none!");
3490                         return traded;
3491                 }
3492         }
3493 }
3494
3495 static const char *cmd_help_text =
3496 "Êý¸þ¤ÏÌð°õ¥­¡¼(¥Æ¥ó¥­¡¼)¤Ç¼¨¤¹¡£\n"
3497 "ESC¤ò²¡¤¹¤ÈÌ¿Îá¤òÃæÃǤ¹¤ë¡£\n"
3498 "Ì¿Îá¤Ï¼¡¤ÎÄ̤ê¤Ç¤¢¤ë¡£\n"
3499 "\n"
3500 "A)²¿¤«¤ò¹¶·â¤¹¤ë\n"
3501 "B)Á¥¤Ê¤É¤Ë¾è¤ë\n"
3502 "C)¼öʸ¤ò¾§¤¨¤ë\n"
3503 "E)Ä®¤äƶ·¢¤ËÆþ¤ë\n"
3504 "F)Á¥¤ÎÂçˤ¤Ê¤É¤Çˤ·â¤¹¤ë\n"
3505 "G)ÃÖ¤«¤ì¤¿¤â¤Î¤ò¼è¤ë\n"
3506 "H)¥ì¥Ð¡¼¤äµ¡³£¤òÁàºî¤¹¤ë\n"
3507 "K)¥Ù¥Ã¥É¤ä¹ÓÌî¤ÇµÙ©¤ò¼è¤ë\n"
3508 "L)¤·¤Ð¤é¤¯¤¦¤í¤Ä¤¯\n"
3509 "N)½ç½ø¤òÊѹ¹¤¹¤ë\n"
3510 "O)È¢¤äÈâ¤Ê¤É¤ò³«¤¯\n"
3511 "Q)¥²¡¼¥à¤ò½ªÎ»¤¹¤ë\n"
3512 "R)Éð´ï¤äËɶñ¤òÁõÈ÷¤¹¤ë\n"
3513 "S)±£¤µ¤ì¤¿¤â¤Î¤òõ¤¹\n"
3514 "T)狼¤ÈÏä¹\n"
3515 "U)»ý¤Áʪ¤ò»È¤¦\n"
3516 #ifdef USE_SKILLS
3517 "Y)ǽÎϤò»È¤¦\n"
3518 #endif
3519 "Z)¾õÂÖ¤òɽ¼¨¤¹¤ë\n"
3520 "X)¤¢¤¿¤ê¤òÄ´¤Ù¤ë\n"
3521 "@)¾ì½ê¤ä»þ´Ö¤Ë¤Ä¤¤¤Æɽ¼¨¤¹¤ë\n"
3522 "<space> ²¿¤â¤·¤Ê¤¤\n"
3523 "CTRL-Q)Êݸ¤»¤º¥²¡¼¥à¤ò½ªÎ»¤¹¤ë\n"
3524 "CTRL-S)½ªÎ»¤»¤º¥²¡¼¥à¤òÊݸ¤¹¤ë\n"
3525 "CTRL-R)ºÇ¸å¤ËÊݸ¤·¤¿¾õÂÖ¤òÆɤ߹þ¤à\n"
3526 "²ñÏÃÃæ¤Ë<Tab>¥¢¥ë¥Õ¥¡¥Ù¥Ã¥È¡¦¥í¡¼¥Þ»ú¤ÎÀÚÂØ\n"
3527 "\n"
3528 "²ñÏÃÃæ¤Ï¥­¡¼¥ï¡¼¥É¤òÆþÎϤ¹¤ë¡£Â¿¤¯¤Î¿Íʪ¤Ï¡¢\n"
3529 "̾Á°¡¢»Å»ö¡¢¼è°ú¡¢Ãç´Ö¤ËÂФ·¤ÆÈ¿±þ¤¹¤ë¡£¤³¤¿\n"
3530 "¤¨¤Ë¤Ï¹¹¤Ê¤ë¥­¡¼¥ï¡¼¥É¤Î¼ê¤¬¤«¤ê¤¬´Þ¤Þ¤ì¤Æ¤¤\n"
3531 "¤ë¤³¤È¤¬¤¢¤ë¡£\n"
3532 ;
3533
3534 void cmdHelp(void)
3535 {
3536         struct KeyHandler kh;
3537
3538         foogodSetHintText(PAGER_HINT);
3539         foogodSetMode(FOOGOD_HINT);
3540         statusSetPageText("Ì¿Îá", cmd_help_text);
3541         statusSetMode(Page);
3542
3543         kh.fx = scroller;
3544         kh.data = NULL;
3545         eventPushKeyHandler(&kh);
3546         eventHandle();
3547         eventPopKeyHandler();
3548
3549         statusSetMode(ShowParty);
3550         foogodSetMode(FOOGOD_DEFAULT);
3551 }
3552
3553 void ui_name_vehicle(class Vehicle *vehicle)
3554 {
3555         int yesno;
3556         char buf[64];
3557
3558         log_begin("¤¢¤Ê¤¿¤Î");
3559         vehicle->describe();
3560         log_end("¤Ë̾Á°¤ò¤Ä¤±¤ë¤«¡©");
3561         cmdwin_spush("̾¤Å¤±¤ë");
3562
3563         cmdwin_spush("<y/n>");
3564         getkey(&yesno, yesnokey);
3565         cmdwin_pop();
3566         cmdwin_pop();
3567
3568         if (yesno == 'n') {
3569                 cmdwin_spush("¤¤¤¤¤¨¡ª");
3570                 log_msg("¤Þ¤ë¤ÇÅð¤ó¤À¤â¤Î¤Î¤è¤¦¤À¡ª");
3571                 return;
3572         }
3573
3574         if (!ui_getline(buf, sizeof(buf))) {
3575                 log_msg("¤Þ¤ë¤ÇÅð¤ó¤À¤â¤Î¤Î¤è¤¦¤À¡ª");
3576                 return;
3577         }
3578
3579         vehicle->setName(buf);
3580
3581         log_begin("¤¢¤Ê¤¿¤Ï");
3582         vehicle->describe();
3583         log_end("¤È̾¤Å¤±¤¿¡£");
3584 }
3585
3586 void cmdSettings(void)
3587 {
3588         StatusMode omode = statusGetMode();
3589         options_menu();
3590         statusSetMode(omode);
3591 }
3592
3593 void cmdDrop(class Character *actor)
3594 {
3595         enum StatusMode omode;
3596         struct inv_entry *ie;
3597         class Object *obj;
3598         int maxq, quantity, dir, x, y;
3599
3600         assert(actor);
3601
3602         cmdwin_clear();
3603         cmdwin_spush("ÃÖ¤¯");
3604
3605         omode = statusGetMode();
3606         statusBrowseContainer(actor->getInventoryContainer(), "ÃÖ¤¯");
3607         ie = ui_select_item();
3608         statusSetMode(omode);
3609
3610         if (!ie) {
3611                 return;
3612         }
3613
3614         maxq = ie->count - ie->ref;
3615         assert(maxq);
3616
3617         /* Don't drop quest items in temporary places! */
3618         if (place_is_wilderness_combat(actor->getPlace())
3619             && ie->type->isQuestItem()) {
3620                 log_msg("%s¤Ï½ÅÍפ½¤¦¤À¡£¤³¤³¤ËÃÖ¤¯¤È¼º¤¦¤Ë°ã¤¤¤Ê¤¤¡ª",
3621                         ie->type->getName());
3622                 return;
3623         }
3624
3625         /* prompt for a count (unless there is only one) */
3626         if (ie->count == 1) {
3627                 quantity = 1;
3628         } else {
3629                 quantity = ui_get_quantity(maxq);
3630                 if (!quantity) {
3631                         return;
3632                 }
3633         }
3634
3635         /* prompt for location */
3636         dir = ui_get_direction();
3637         if (dir == CANCEL) {
3638                 return;
3639         }
3640         x = actor->getX() + directionToDx(dir);
3641         y = actor->getY() + directionToDy(dir);
3642
3643         /* put it on the map */
3644         obj = ie->type->createInstance();
3645         assert(obj);
3646         obj->setCount(quantity);
3647         if (place_get_movement_cost(actor->getPlace(), x, y, 
3648                             obj, 0) < PTABLE_NO_DROP)
3649         {
3650                 obj->relocate(actor->getPlace(), x, y,
3651                            REL_NOSTEP, /* FIXME: really? */
3652                         NULL);
3653                 actor->takeOut(ie->type, quantity);
3654                 actor->runHook(OBJ_HOOK_DROP_DONE, "pd", ie->type, quantity);
3655           }
3656           else if (place_get_movement_cost(actor->getPlace(), actor->getX(), actor->getY(), 
3657                             obj, 0) < PTABLE_IMPASSABLE)
3658         {
3659                         obj->relocate(actor->getPlace(), actor->getX(), actor->getY(),
3660                            REL_NOSTEP, /* FIXME: really? */
3661                         NULL);
3662                 actor->takeOut(ie->type, quantity);
3663                 actor->runHook(OBJ_HOOK_DROP_DONE, "pd", ie->type, quantity);
3664                 log_msg("%s¤Ï¹ç¤ï¤Ê¤¤¡ª", ie->type->getName());
3665                  }
3666                  else
3667                  {
3668                          log_msg("%s¤òÃÖ¤±¤Ê¤¤¡ª", ie->type->getName());
3669                  }
3670         /* remove from party inventory */
3671         actor->decActionPoints(kern_intvar_get("AP_COST:drop_item"));
3672
3673         statusRepaint();
3674         mapUpdate(REPAINT_IF_DIRTY);
3675         return;
3676 }
3677
3678 #ifdef USE_SKILLS
3679
3680 static const void *cmd_select_generic()
3681 {
3682         struct KeyHandler kh;
3683         struct ScrollerContext sc;
3684
3685         foogodSetHintText(SCROLLER_HINT);
3686         foogodSetMode(FOOGOD_HINT);        
3687
3688         sc.selector = SelectSuperGeneric;
3689         sc.selection = NULL;
3690         kh.fx = scroller;
3691         kh.data = &sc;
3692
3693         eventPushKeyHandler(&kh);
3694         cmdwin_push("<ÁªÂò>");
3695         eventHandle();
3696         cmdwin_pop();
3697         eventPopKeyHandler();
3698
3699         foogodSetMode(FOOGOD_DEFAULT);
3700         return sc.selection;
3701 }
3702
3703
3704 /* Do common front-end processing. Migrate all commands to start using this. */
3705 static class Character *cmd_front_end(class Character *pc, const char *cmdstr)
3706 {
3707         cmdwin_clear();
3708         cmdwin_spush(cmdstr);
3709
3710         /* prompt user? */
3711         if (!pc) {
3712
3713                 /* only one choice? */
3714                 if (player_party->get_num_living_members() == 1) {
3715                         pc = player_party->get_first_living_member();
3716                         cmdwin_spush(pc->getName());
3717                 } else {
3718                         pc = select_party_member();
3719                 }
3720
3721         } else {
3722                 cmdwin_spush(pc->getName());
3723         }
3724
3725         /* user abort? */
3726         if (!pc) {
3727                 return 0;
3728         }
3729
3730         /* dead actor? */
3731         if (pc->isDead()) {
3732                 log_msg("%s - %s¤Ï»à¤ó¤Ç¤¤¤ë¡ª", cmdstr, pc->getName());
3733                 cmdwin_push("¤Ç¤­¤Ê¤¤¡ª");
3734                 return 0;
3735         }
3736
3737         /* sleeping actor? */
3738         if (pc->isAsleep()) {
3739                 log_msg("%s - %s¤Ï¤Ò¤Ã¤¯¤êÊ֤äƤ¤¤Ó¤­¤ò¤«¤¤¤Æ¤¤¤ë¡ª", cmdstr, 
3740                         pc->getName());
3741                 cmdwin_push("¤Ç¤­¤Ê¤¤¡ª");
3742                 return 0;
3743         }
3744
3745         /* tell status who the actor is (sometimes it matters) */
3746         statusSelectCharacter(pc->getOrder());
3747
3748         return pc;
3749 }
3750
3751 static void cmd_add_skill_set(struct node *head, class Character *pc, 
3752                               struct skill_set *skset)
3753 {
3754         struct list *elem;
3755         int pclvl = pc->getLevel();
3756
3757         /* for each skill in the skill set */
3758         list_for_each(&skset->skills, elem) {
3759
3760                 struct skill_set_entry *ssent;
3761                 struct node *node;
3762                 ssent = list_entry(elem, struct skill_set_entry, list);
3763
3764                 /* is it a passive skill? */
3765                 if (ssent->skill->passive) {
3766                         continue;
3767                 }
3768
3769                 /* is the character is of sufficient level? */
3770                 if (pclvl < ssent->level) {
3771                         continue;
3772                 }
3773
3774                 /* add it to the list */
3775                 node = node_new(ssent);
3776                 node_add_tail(head, node);
3777         }
3778 }
3779
3780 static void cmd_build_skill_list(struct node *head, class Character *pc)
3781 {
3782         node_init(head);
3783
3784         /* add species skills */
3785         if (pc->species
3786             && pc->species->skills) {
3787                 cmd_add_skill_set(head, pc, pc->species->skills);
3788         }
3789
3790         /* add occupation skills */
3791         if (pc->occ
3792             && pc->occ->skills) {
3793                 cmd_add_skill_set(head, pc, pc->occ->skills);
3794         }
3795
3796         /* add bonus skills? */
3797 }
3798
3799 static int cmd_paint_skill(struct stat_super_generic_data *self, 
3800                             struct node *node, 
3801                             SDL_Rect *rect)
3802 {
3803         struct skill_set_entry *ssent = (struct skill_set_entry *)node->ptr;
3804         struct skill *skill = ssent->skill;
3805         const char *requires = "Requires:";
3806         struct node *tnode;
3807         struct list *elem;
3808         SDL_Rect orect;
3809         int complete = 0;
3810
3811         /* remember original rect */
3812         orect = *rect;
3813
3814         /* name */
3815         if (rect->h < ASCII_H) {
3816                 return -1;
3817         }
3818         screenPrint(rect, 0, "^c+m%s^c-", skill->name);
3819
3820         /* level, ap, mp */
3821         screenPrint(rect, SP_RIGHTJUSTIFIED, 
3822                     "^c+G¥ì¥Ù¥ë:^c+y%d^c- ËâÎÏ:^c+b%d^c- ¹ÔÆ°:^c+r%d^c-^c-",
3823                     ssent->level, 
3824                     skill->mp, 
3825                     skill->ap);
3826         rect->y += ASCII_H;
3827         rect->h -= ASCII_H;
3828
3829         /* check for required items */
3830         if (! node_list_empty(&skill->tools)
3831             || ! list_empty(&skill->materials)) {
3832
3833                 if (rect->h < ASCII_H) {
3834                         complete = -1;
3835                 } else {
3836
3837                         /* print "requires:" */
3838                         screenPrint(rect, 0, " ^c+G%s^c-", requires);
3839                         
3840                         /* temporarily change x to print to right of "requires" */
3841                         rect->x += (strlen(requires) + 1) * ASCII_W;
3842                         
3843                         /* list tools */
3844                         node_for_each(&skill->tools, tnode) {
3845
3846                                 if (rect->h < ASCII_H) {
3847                                         complete = -1;
3848                                         break;
3849                                 }
3850
3851                                 class ObjectType *tool = (class ObjectType*)tnode->ptr;
3852                                 struct inv_entry *ie=player_party->inventory->
3853                                         search(tool);
3854                                 char tool_clr=(ie&&ie->count)?'g':'r';
3855                                 screenPrint(rect, 0, "^c+%c%s^c-", tool_clr, 
3856                                             tool->getName());
3857
3858                                 rect->y += ASCII_H;
3859                                 rect->h -= ASCII_H;
3860                         }
3861
3862                         /* list materials */
3863                         list_for_each(&skill->materials, elem) {
3864
3865                                 if (rect->h < ASCII_H) {
3866                                         complete = -1;
3867                                         break;
3868                                 }
3869
3870                                 struct skill_material *mat =
3871                                         list_entry(elem, struct skill_material, list);
3872                                 class ObjectType *objtype = 
3873                                         (class ObjectType*)mat->objtype;
3874                                 struct inv_entry *ie=player_party->inventory->
3875                                         search(objtype);
3876                                 char mat_clr=ie?'g':'r';
3877                                 char q_clr=(ie&&(ie->count>=mat->quantity))?'g':'r';
3878                                 screenPrint(rect, 0, "^c+%c%s^c+%c (%d/%d)^c-^c-", 
3879                                             mat_clr,
3880                                             objtype->getName(), 
3881                                             q_clr,
3882                                             mat->quantity,
3883                                             ie?ie->count:0);
3884
3885                                 rect->y += ASCII_H;
3886                                 rect->h -= ASCII_H;
3887                         }
3888
3889                         /* restore rect x */
3890                         rect->x = orect.x;
3891                 }
3892         }
3893         
3894         /* figure out how much area we used */
3895         orect.h = rect->y - orect.y;
3896
3897         /* if this is not the currently selected item then shade it */
3898         if (self->selected != node) {
3899                 screenShade(&orect, 128);
3900         }
3901
3902         return complete;
3903 }
3904
3905 static void cmd_skill_list_unref(struct stat_super_generic_data *self)
3906 {
3907         struct node *node;
3908
3909         /* Decrement the refcount. */
3910         assert(self->refcount > 0);
3911         self->refcount--;
3912         if (self->refcount > 0) {
3913                 return;
3914         }
3915
3916         /* Cleanup if no more refs. */
3917         node = node_next(&self->list);
3918         while (node != &self->list) {
3919                 struct node *tmp = node;
3920                 node = node_next(node);
3921                 node_unref(tmp);
3922         }
3923 }
3924
3925 static struct skill_set_entry *cmd_select_skill(class Character *pc)
3926 {
3927         struct skill_set_entry *ssent;
3928         struct node *selected;
3929         struct stat_super_generic_data data;
3930
3931         /* setup the status browser data */
3932         memset(&data, 0, sizeof(data));
3933         cmd_build_skill_list(&data.list, pc);
3934         data.title = "ǽÎÏ";
3935         data.paint = cmd_paint_skill;
3936         data.unref = cmd_skill_list_unref;
3937
3938         /* put the status browser in selection mode */
3939         statusSetSuperGenericData(&data);
3940         statusPushMode(SuperGeneric);
3941
3942         /* wait for user selection */
3943         selected = (struct node*)cmd_select_generic();
3944
3945         /* extract result */
3946         if (selected) {
3947                 ssent = (struct skill_set_entry *)selected->ptr;
3948                 cmdwin_push(ssent->skill->name);
3949         } else {
3950                 ssent = 0;
3951                 cmdwin_push("²¿¤â¤·¤Ê¤¤");
3952         }
3953
3954         /* restore browser status mode */
3955         statusPopMode();
3956
3957         assert(! data.refcount);
3958
3959         return ssent;
3960 }
3961
3962 void cmdYuse(class Character *actor)
3963 {
3964         struct skill_set_entry *ssent;
3965         struct skill *skill;
3966         int cant = 0, result = 0, yused = 0;
3967
3968         /* select/verify the actor */
3969         if (!(actor = cmd_front_end(actor, "ǽÎÏ"))) {
3970                 return;
3971         }
3972
3973         /* select the skill to yuse */
3974         if (!(ssent = cmd_select_skill(actor))) {
3975                 return;
3976         }
3977         skill = ssent->skill;
3978         log_begin("%s: %s - ", actor->getName(), skill->name);
3979
3980         /* check wilderness */
3981         if (! skill->wilderness_ok
3982             && place_is_wilderness(actor->getPlace())) {
3983                 cant = 1;
3984                 log_msg("¹ÓÌî¤Ç¤Ï»È¤¨¤Ê¤¤¡ª");
3985         }
3986
3987         /* check level */
3988         if (actor->getLevel() < ssent->level) {
3989                 cant = 1;
3990                 log_msg("¥ì¥Ù¥ë%d°Ê¾åɬÍפÀ¡ª", ssent->level);
3991         }
3992
3993         /* check mana */
3994         if (actor->getMana() < skill->mp) {
3995                 cant = 1;
3996                 log_msg("ËâÎϤ¬Â­¤ê¤Ê¤¤¡ª");
3997         }
3998
3999         /* check tools */
4000         if (!node_list_empty(&skill->tools)) {
4001                 struct node *tnode;
4002                 node_for_each(&skill->tools, tnode) {
4003                         class ObjectType *tool = (class ObjectType*)tnode->ptr;
4004                         struct inv_entry *ie=player_party->inventory->
4005                                 search(tool);
4006                         if (!ie || !ie->count) {
4007                                 log_msg("%s¤¬É¬ÍפÀ¡ª", tool->getName());
4008                                 cant = 1;
4009                         }
4010                 }
4011
4012         }
4013
4014         /* check material */
4015         if (! list_empty(&skill->materials)) {
4016                 struct list *elem;
4017                 struct skill_material *mat;
4018                 class ObjectType *objtype;
4019                 struct inv_entry *ie;
4020                 list_for_each(&skill->materials, elem) {
4021                         mat = list_entry(elem, struct skill_material, list);
4022                         objtype = (class ObjectType*)mat->objtype;
4023                         ie = player_party->inventory->search(objtype);
4024                         if (!ie || ie->count < mat->quantity) {
4025                                 cant = 1;
4026                                 log_msg("%d¤Ä¤Î%s¤¬É¬ÍפÀ¡ª", mat->quantity, 
4027                                         objtype->getName());
4028                         }
4029                 }
4030         }
4031
4032         /* check special */
4033         if (skill->can_yuse
4034             && ! closure_exec(skill->can_yuse, "p", actor)) {
4035                 cant = 1;
4036         }
4037
4038         /* cant? */
4039         if (cant) {
4040                 cmdwin_push("¼ºÇÔ¡ª");
4041                 log_end("^c+r¼ºÇÔ¡ª^c-");
4042                 return;
4043         }
4044
4045         /* yuse the skill */
4046         result = closure_exec(skill->yuse, "p", actor);
4047         yused = cmd_eval_and_log_result(result);
4048         
4049         /* change ap/mp/xp and consume materials */
4050         if (yused) {
4051                 actor->runHook(OBJ_HOOK_YUSE_DONE, 0);
4052                 actor->addMana(0 - skill->mp);
4053                 actor->decActionPoints(skill->ap);
4054                 actor->addExperience(ssent->level);
4055
4056                 if (! list_empty(&skill->materials)) {
4057                         struct list *elem;
4058                         struct skill_material *mat;
4059                         list_for_each(&skill->materials, elem) {
4060                                 mat = list_entry(elem, struct skill_material, 
4061                                                  list);
4062                                 player_party->takeOut((class ObjectType*)
4063                                                       mat->objtype, 
4064                                                       mat->quantity);
4065                         }
4066                 }
4067         }       
4068
4069         log_end(0);
4070 }
4071 #endif /* USE_SKILLS */
4072
4073 bool cmdSetSoloMode(int party_member_index)
4074 {
4075     class Character *solo_member = player_party->getMemberAtIndex(party_member_index);
4076     if (solo_member
4077         && ! solo_member->isIncapacitated() 
4078         && solo_member->isOnMap()
4079         && solo_member->isPlayerControlled()
4080         ) {
4081
4082         if (solo_member->engagedInTask()) {            
4083             log_msg("%s¤Ï%s¤·¤Æ¤¤¤ë¡£ÃæÃǤ¹¤ë¤«¡©", solo_member->getName(), solo_member->getTaskName());
4084             if (! ui_get_yes_no(solo_member->getName())) {
4085                 return false;
4086             }
4087         }
4088
4089         player_party->enableSoloMode(solo_member);
4090         return true;
4091     }
4092     return false;
4093 }
4094
4095 bool cmdToggleFollowMode(void)
4096 {
4097     log_begin("ÄÉÀ×");
4098     if (player_party->getPartyControlMode() == PARTY_CONTROL_FOLLOW) {
4099         log_end("¤·¤Ê¤¤¡£");
4100         player_party->enableRoundRobinMode();
4101         return false;
4102     } else {
4103         log_end("¤¹¤ë¡£");
4104         player_party->enableFollowMode();
4105         return true;
4106     }   
4107 }
4108