1 // nazghul - an old-school RPG engine
2 // Copyright (C) 2002, 2003 Gordon McNutt
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)
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
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
19 // gmcnutt@users.sourceforge.net
23 #include "../config.h" /* for USE_SKILLS */
26 #include "constants.h"
46 #include "Container.h"
47 #include "dup_constants.h"
60 #include "kern_intvar.h"
62 #include "skill_set.h"
63 #include "skill_set_entry.h"
66 #include "nazghul.h" // for DeveloperMode
68 #include "terrain_editor.h"
77 #include <unistd.h> // getpid()
80 #define ESCAPE_CHARACTER 110
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
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);
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.
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 */
110 static class Character *cmd_front_end(class Character *pc, const char *cmdstr);
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,
116 struct list *suggest,
117 v_fncptr_iiv_t each_tile_func,
118 i_fncptr_iiv_t each_target_func);
122 static class Character * cmdAnyPartyMemberEngagedInTask(void)
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()) {
134 int dirkey(struct KeyHandler *kh, int key, int keymod)
136 int *dir = (int *) kh->data;
138 if (key >= KEY_SOUTHWEST && key <= KEY_NORTHEAST) {
139 *dir = keyToDirection(key);
143 if (key == SDLK_ESCAPE) {
148 /* Special case: let '.' mean KEY_HERE for the numeric keypad
151 *dir = keyToDirection(KEY_HERE);
158 int cardinaldirkey(struct KeyHandler *kh, int key, int keymod)
160 int *dir = (int *) kh->data;
167 *dir = keyToDirection(key);
171 if (key == SDLK_ESCAPE) {
179 int yesnokey(struct KeyHandler * kh, int key, int keymod)
181 int *yesno = (int *) kh->data;
198 enum get_number_state {
205 /* Max number getnum() will accept */
206 const int MAX_GETNUM = 999999999;
208 struct get_number_info {
214 struct get_char_info {
221 struct get_spell_name_data {
222 char spell_name[MAX_WORDS_IN_SPELL_NAME + 1];
229 int getnum(struct KeyHandler *kh, int key, int keymod)
231 struct get_number_info *info;
233 info = (struct get_number_info *) kh->data;
235 switch (info->state) {
240 info->state = GN_CANCEL;
251 info->state = GN_ZERO;
256 info->digit = info->digit * 10 + key - '0';
257 cmdwin_push("%c", key);
258 info->state = GN_SOME;
265 info->state = GN_CANCEL;
274 cmdwin_spush(info->prompt);
275 info->state = GN_ALL;
282 info->digit = info->digit * 10 + key - '0';
283 cmdwin_push("%c", key);
284 info->state = GN_SOME;
291 info->state = GN_CANCEL;
298 info->digit = info->digit - (info->digit % 10);
301 if (info->digit == 0) {
302 info->state = GN_ALL;
304 cmdwin_spush(info->prompt);
309 int keyval = key - '0';
310 if ((MAX_GETNUM - keyval) >= info->digit) {
311 info->digit = info->digit * 10 + keyval;
312 cmdwin_push("%c", key);
322 int getdigit(struct KeyHandler * kh, int key, int keymod)
324 struct get_number_info *info;
326 info = (struct get_number_info *) kh->data;
336 info->digit = key - '0';
337 if (info->digit != 0)
338 cmdwin_push("%c", key);
345 static int cmd_getchar(struct KeyHandler * kh, int key, int keymod)
347 struct get_char_info *info;
349 info = (struct get_char_info *) kh->data;
357 if (strchr(info->string, key)) {
360 cmdwin_push("%c", key);
367 int anykey(struct KeyHandler * kh, int key, int keymod)
372 int scroller(struct KeyHandler * kh, int key, int keymod)
374 struct ScrollerContext *context;
375 context = (struct ScrollerContext *) kh->data;
379 statusScroll(ScrollUp);
382 statusScroll(ScrollDown);
385 statusScroll(ScrollRight);
388 statusScroll(ScrollLeft);
391 statusScroll(ScrollPageUp);
394 statusScroll(ScrollPageDown);
400 if (context != NULL) {
402 statusGetSelected(context->selector);
411 if (context && context->mixing) {
423 bool mouse_button_cursor(struct MouseButtonHandler *mh, SDL_MouseButtonEvent *event)
425 struct movecursor_data * data
426 = (struct movecursor_data *) mh->data;
431 if (mapScreenToPlaceCoords(&mx, &my)) {
435 /* Did the crosshair move? */
436 if (Session->crosshair->getX() != mx
437 || Session->crosshair->getY() != my) {
439 /* turn on range shading after the first move */
440 Session->crosshair->shadeRange(true);
442 /* Move the crosshair */
443 Session->crosshair->move(mx - Session->crosshair->getX(),
444 my - Session->crosshair->getY());
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(),
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(),
465 return 1; /* target selected */
472 bool mouse_motion_cursor(struct MouseMotionHandler *mh, SDL_MouseMotionEvent *event)
474 struct movecursor_data * data
475 = (struct movecursor_data *) mh->data;
480 if (mapScreenToPlaceCoords(&mx, &my)) {
484 /* Did the crosshair NOT move? */
485 if (Session->crosshair->getX() == mx
486 && Session->crosshair->getY() == my) {
490 /* turn on range shading after the first move */
491 Session->crosshair->shadeRange(true);
493 /* Move the crosshair */
494 Session->crosshair->move(mx - Session->crosshair->getX(),
495 my - Session->crosshair->getY());
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(),
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(),
520 * movecursor - move the crosshair around, possibly running a function on each
521 * tile entered by the crosshair or on each tile selected
523 int movecursor(struct KeyHandler * kh, int key, int keymod)
526 struct movecursor_data * data
527 = (struct movecursor_data *) kh->data;
529 /* target selected? */
535 if (data->each_target_func) {
536 return data->each_target_func(Session->crosshair->getPlace(),
537 Session->crosshair->getX(),
538 Session->crosshair->getY(),
541 return 1; /* target selected */
546 /* crosshairs moved? */
547 if (keyIsDirection(key)) {
548 int dir = keyToDirection(key);
549 int dx = directionToDx(dir);
550 int dy = directionToDy(dir);
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,
560 } else if (isdigit(key)) {
561 data->jump = key - '0';
563 data->jump = 1; /* disallow zero */
566 struct list *old_loc = data->cur_loc;
580 && ! list_empty(data->loc_list)) {
581 data->cur_loc = data->cur_loc->next;
582 if (data->cur_loc == data->loc_list) {
592 /* Previous target */
594 && ! list_empty(data->loc_list)) {
595 data->cur_loc = data->cur_loc->prev;
596 if (data->cur_loc == data->loc_list) {
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(),
614 Session->crosshair->getY());
619 /* Cursor was moved? */
623 if (data->each_tile_func) {
624 data->each_tile_func(Session->crosshair->getPlace(),
625 Session->crosshair->getX(),
626 Session->crosshair->getY(),
630 /* turn on range shading after the first move */
631 Session->crosshair->shadeRange(true);
634 return 0; /* not done */
637 struct inv_entry *ui_select_item(void)
639 struct inv_entry *ie;
640 struct KeyHandler kh;
641 struct ScrollerContext sc;
643 foogodSetHintText(SCROLLER_HINT);
644 foogodSetMode(FOOGOD_HINT);
646 sc.selector = InventoryItem;
651 eventPushKeyHandler(&kh);
652 cmdwin_push("<ÁªÂò>");
655 eventPopKeyHandler();
657 foogodSetMode(FOOGOD_DEFAULT);
659 ie = (struct inv_entry *) sc.selection;
661 cmdwin_push("²¿¤â¤·¤Ê¤¤¡ª");
665 cmdwin_spush(ie->type->getName());
670 class Character *select_party_member(void)
672 enum StatusMode omode;
673 class Character *character;
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());
682 foogodSetHintText(SCROLLER_HINT);
683 foogodSetMode(FOOGOD_HINT);
684 omode = statusGetMode();
685 statusSetMode(SelectCharacter);
687 struct KeyHandler kh;
688 struct ScrollerContext sc;
689 sc.selector = Character;
694 eventPushKeyHandler(&kh);
695 cmdwin_push("<ÁªÂò>");
698 eventPopKeyHandler();
702 character = (class Character *) sc.selection;
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
712 /* fixme: move to cmd_front_end? */
713 cmdwin_spush("%s", character->getName());
716 statusSetMode(omode);
717 foogodSetMode(FOOGOD_DEFAULT);
722 void getkey(void *data, int(*handler) (struct KeyHandler * kh, int key, int keymod))
724 struct KeyHandler kh;
728 eventPushKeyHandler(&kh);
730 eventPopKeyHandler();
733 int ui_get_direction(void)
736 cmdwin_push("<Êý¸þ>");
737 getkey(&dir, dirkey);
740 cmdwin_push("²¿¤â¤·¤Ê¤¤¡ª");
742 cmdwin_spush(directionToString(dir));
747 static void search_visitor(class Object *obj, void *arg)
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);
757 bool cmdSearch(class Character *pc)
762 struct place *place = 0;
765 cmdwin_spush("õ¤¹");
767 /* FIXME: this is duplicated in cmdHandle(), these command functions
768 * all need to be cleaned up to ensure consistency. */
770 if (player_party->get_num_living_members() == 1) {
771 pc = player_party->get_first_living_member();
772 cmdwin_spush("%s", pc->getName());
774 pc = select_party_member();
782 place = pc->getPlace();
786 dir = ui_get_direction();
790 x2 = x + directionToDx(dir);
791 y2 = y + directionToDy(dir);
793 /* Caution: searching can destroy the pc if it triggers traps. The
794 * following is iterative, so protect the pc from destruction until it
797 place_for_each_object_at(place, x2, y2, search_visitor, pc);
803 place_describe(place, x2, y2, PLACE_DESCRIBE_ALL);
804 log_end("¤ò¸«¤Ä¤±¤¿¡£");
806 pc->decActionPoints(kern_intvar_get("AP_COST:search")); // SAM: We may want a '-1' value here, to signify "all remaining AP"...
811 static int cmdGetFilter(class Object *obj)
813 return (int)(obj->getObjectType() &&
814 obj->getObjectType()->canGet());
817 bool cmdGet(class Object *actor)
824 cmdwin_spush("¼è¤ë");
826 dir = ui_get_direction();
831 x = actor->getX() + directionToDx(dir);
832 y = actor->getY() + directionToDy(dir);
834 item = place_get_filtered_object(actor->getPlace(), x, y,
837 log_msg("¼è¤ë - ²¿¤â¤Ê¤¤¡ª");
843 while (NULL != (item = place_get_filtered_object(
845 x, y, cmdGetFilter)))
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))
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...
866 static void cmd_describe_inv_entry(struct inv_entry *ie, void *unused)
869 ie->type->describeType(ie->count);
873 bool cmdOpen(class Character * pc)
877 class Container *container;
880 cmdwin_spush("³«¤¯");
882 // Get the party member who will open the container (in combat mode
883 // this is passed in as a parameter).
885 cmdwin_spush(pc->getName());
887 pc = select_party_member();
893 dir = ui_get_direction();
898 x = place_wrap_x(pc->getPlace(),
899 pc->getX() + directionToDx(dir));
900 y = place_wrap_y(pc->getPlace(),
901 pc->getY() + directionToDy(dir));
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));
909 /* Check for a mechanism */
910 mech = place_get_object(pc->getPlace(), x, y, mech_layer);
912 /* Check for a container */
913 container = (class Container *) place_get_object(Place, x, y,
916 /* ignore invisible objects unless Reveal is in effect */
918 if (mech && ! mech->isVisible())
920 if (container && ! container->isVisible())
924 /* If both are present the user must select one */
925 if (mech && mech->getObjectType()->canOpen() && container) {
927 enum StatusMode omode;
928 struct stat_list_entry statlist[2];
929 struct KeyHandler kh;
930 struct ScrollerContext data;
932 cmdwin_push("<ÁªÂò>");
934 statlist[0].sprite = mech->getSprite();
935 snprintf(statlist[0].line1, sizeof(statlist[0].line1), "%s",
937 statlist[0].line2[0] = 0;
938 statlist[0].data = mech;
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;
946 foogodSetHintText(SCROLLER_HINT);
947 foogodSetMode(FOOGOD_HINT);
948 omode = statusGetMode();
949 statusSetGenericList("ÂоÝ", 2, statlist);
950 statusSetMode(GenericList);
952 data.selection = NULL;
953 data.selector = Generic;
956 eventPushKeyHandler(&kh);
958 eventPopKeyHandler();
960 statusSetMode(omode);
961 foogodSetMode(FOOGOD_DEFAULT);
963 /* Disqualify the object NOT selected */
964 if (data.selection == mech)
972 /* Open a mechanism */
973 if (mech && mech->getObjectType()->canOpen()) {
974 cmdwin_push("%s!", mech->getName());
975 mech->getObjectType()->open(mech, pc);
977 pc->runHook(OBJ_HOOK_OPEN_DONE, "p", mech);
978 pc->decActionPoints(kern_intvar_get("AP_COST:open_mechanism"));
982 /* Nothing to open */
983 if (NULL == container) {
984 cmdwin_push("Ãæ»ß¡ª");
985 log_msg("³«¤¯ - ²¿¤â¤Ê¤¤¡ª");
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());
997 // Describe the contents of the container.
998 log_msg("¸«¤Ä¤±¤¿¤â¤Î:");
999 container->forEach(cmd_describe_inv_entry, NULL);
1001 // Open the container (automagically spills all the contents onto the
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.
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 // --------------------------------------------------------------------
1021 container->remove();
1029 static bool cmd_nop_qh(struct QuitHandler *kh)
1038 struct QuitHandler qh;
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? */
1046 eventPushQuitHandler(&qh);
1049 cmdwin_spush("½ªÎ»¤¹¤ë");
1050 cmdwin_spush("<y/n>");
1051 getkey(&yesno, yesnokey);
1056 cmdwin_spush("Ãæ»ß¡ª");
1061 cmdwin_spush("Êݸ¤¹¤ë");
1062 cmdwin_spush("<y/n>");
1063 getkey(&yesno, yesnokey);
1068 cmdwin_spush("Êݸ¤·¤Ê¤¤¡ª");
1074 cmdwin_spush("Êݸ¤·¤¿¡ª");
1075 log_msg("¤µ¤è¤¦¤Ê¤é¡ª\n");
1082 eventPopQuitHandler();
1087 void cmdAttack(void)
1090 struct move_info info;
1091 struct combat_info cinfo;
1093 // Initialize data structures.
1094 memset(&info, 0, sizeof(info));
1095 memset(&cinfo, 0, sizeof(cinfo));
1097 cinfo.defend = false;
1099 // Get the direction
1101 cmdwin_spush("¹¶·â¤¹¤ë");
1102 cmdwin_spush("<Êý¸þ>");
1103 getkey(&dir, cardinaldirkey);
1105 if (dir == CANCEL) {
1106 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1109 cmdwin_spush("%s", directionToString(dir));
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);
1119 if (info.npc_party == NULL) {
1120 cmdwin_spush("ï¤â¤¤¤Ê¤¤¡ª");
1121 log_msg("¹¶·â¤¹¤ë - ï¤â¤¤¤Ê¤¤¡ª");
1124 info.px = player_party->getX();
1125 info.py = player_party->getY();
1127 cmdwin_spush("%s", info.npc_party->getName());
1129 // If the npc is not hostile then get player confirmation.
1130 if (! are_hostile(info.npc_party, player_party)) {
1132 cmdwin_spush("Ũ¤Ç¤Ê¤¤¼Ô¤ò¹¶·â¤¹¤ë");
1133 cmdwin_spush("<y/n>");
1134 getkey(&yesno, yesnokey);
1137 cmdwin_spush("¤¤¤¤¤¨");
1140 cmdwin_spush("¤Ï¤¤");
1142 make_hostile(info.npc_party, player_party);
1147 info.npc_party->describe();
1148 log_end("¤ò¹¶·â¤·¤¿¡£");
1151 combat_enter(&cinfo);
1154 void cmdDeveloperEval(struct session *session)
1156 unsigned int len = 1024;
1157 char *buf = (char*)calloc(len, sizeof(char));
1159 log_msg("Eval: not enough memory!");
1164 cmdwin_push("Eval:");
1166 if (!ui_getline_filtered(buf, len, NULL)) {
1167 log_msg("Eval: abort");
1168 cmdwin_push("abort!");
1172 log_msg("Eval: %s", buf);
1173 session_eval(session, buf);
1184 cmdwin_spush("ˤ·â¤¹¤ë");
1186 class Vehicle *vehicle = player_party->getVehicle();
1188 !vehicle->getOrdnance())) {
1190 // In future, we may check for adjacent "cannon"
1191 // mechanisms here (as in U5).
1192 cmdwin_spush("ˤ·â¤Ç¤¤Ê¤¤¡ª");
1193 log_msg("ˤ·â¤¹¤ë - Âçˤ¤¬¤Ê¤¤¡ª");
1197 cmdwin_spush("%s", vehicle->getOrdnance()->getName());
1198 cmdwin_spush("<Êý¸þ>");
1199 getkey(&dir, dirkey);
1202 if (dir == CANCEL) {
1203 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1207 cmdwin_spush("%s", directionToString(dir));
1208 if (! vehicle->fire_weapon(directionToDx(dir),
1211 cmdwin_spush("¦ÌÌÊý¸þ¤Ç¤Ê¤¤¡ª");
1212 log_msg("ˤ·â¤¹¤ë - ¦ÌÌÊý¸þ¤Ç¤Ê¤¤¡ª");
1217 bool cmdReady(class Character * member)
1219 bool committed = false;
1220 struct inv_entry *ie;
1221 struct KeyHandler kh;
1222 struct ScrollerContext sc;
1223 const char *msg = 0;
1226 cmdwin_spush("ÁõÈ÷¤¹¤ë");
1230 cmdwin_spush("%s", member->getName());
1232 member = select_party_member();
1236 if (member->isCharmed()) {
1237 cmdwin_push("ËâË¡¤¬¤«¤±¤é¤ì¤Æ¤¤¤ë¡ª");
1238 log_msg("ÁõÈ÷¤¹¤ë - ËâË¡¤¬¤«¤±¤é¤ì¤Æ¤¤¤ë¡ª");
1245 log_msg("%s¤ÎÁõÈ÷:", member->getName());
1247 statusSelectCharacter(member->getOrder());
1249 player_party->sortReadiedItems(member);
1250 foogodSetHintText(SCROLLER_HINT);
1251 foogodSetMode(FOOGOD_HINT);
1252 statusSetMode(Ready);
1253 sc.selector = InventoryItem;
1256 eventPushKeyHandler(&kh);
1258 cmdwin_spush("<ÁªÂò/ESC>");
1262 sc.selection = NULL;
1267 ie = (struct inv_entry *) sc.selection;
1269 cmdwin_spush("½ª¤¨¤¿¡ª");
1275 class ArmsType *arms = (class ArmsType *) ie->type;
1277 log_begin("%s - ", arms->getName());
1279 if (ie->ref && member->unready(arms)) {
1281 member->decActionPoints(arms->getRequiredActionPoints());
1285 switch (member->ready(arms)) {
1286 case Character::Readied:
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
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
1298 //statusSetMode(Ready);
1300 case Character::NoAvailableSlot:
1301 msg = "»ý¤Á¤¤ì¤Ê¤¤¡ª";
1303 case Character::WrongType:
1306 case Character::TooHeavy:
1315 cmdwin_spush("%s %s", arms->getName(), msg);
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))
1327 eventPopKeyHandler();
1328 statusSetMode(ShowParty);
1329 foogodSetMode(FOOGOD_DEFAULT);
1332 player_party->sortReadiedItems(member);
1333 member->runHook(OBJ_HOOK_READY_DONE, 0);
1341 static void cmd_init_movecursor_data(struct movecursor_data *data,
1342 struct list *suggest)
1344 struct list *entry = 0;
1346 memset(data, 0, sizeof(*data));
1352 /* Copy the head of the list. */
1353 data->loc_list = suggest;
1354 data->cur_loc = data->loc_list;
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;
1368 int select_target(int ox, int oy, int *x, int *y, int range,
1369 struct list *suggest)
1371 return select_target_rlcb(Place, ox, oy, x, y, range, suggest, 0, 0);
1374 void ui_select_target_req_init(ui_select_target_req_t *req)
1376 memset(req, 0, sizeof(*req));
1377 list_init(&req->suggest);
1380 static int select_target_rlcb(struct place *place,
1384 struct list *suggest,
1385 v_fncptr_iiv_t each_tile_func,
1386 i_fncptr_iiv_t each_target_func)
1388 ui_select_target_req_t req;
1391 /* convert args to a targeting request */
1392 ui_select_target_req_init(&req);
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);
1403 list_move(&req.suggest, suggest);
1406 /* call generic target selection */
1407 ret = ui_select_target_generic(&req);
1413 list_move(suggest, &req.suggest);
1415 templ_unref(req.tiles);
1420 int ui_select_target_generic(ui_select_target_req_t *req)
1422 struct movecursor_data data;
1423 struct KeyHandler kh;
1424 struct MouseButtonHandler mbh;
1425 struct MouseMotionHandler mmh;
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;
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;
1442 mbh.fx = mouse_button_cursor;
1445 mmh.fx = mouse_motion_cursor;
1448 eventPushMouseButtonHandler(&mbh);
1449 eventPushKeyHandler(&kh);
1450 cmdwin_spush("<ÂоÝ> (ESC¤ÇÃæ»ß)");
1453 eventPopKeyHandler();
1454 eventPopMouseButtonHandler();
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);
1464 cmdwin_spush("½ª¤¨¤¿¡£");
1471 int select_target_with_doing(int ox, int oy, int *x, int *y,
1473 v_fncptr_iiv_t each_tile_func,
1474 i_fncptr_iiv_t each_target_func)
1476 return select_target_rlcb(Place, ox, oy, x, y, range, 0,
1481 bool cmdHandle(class Character * pc)
1483 // SAM: Adding (H)andle command...
1488 cmdwin_spush("Áàºî¤¹¤ë");
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.
1495 cmdwin_spush("%s", pc->getName());
1497 // Must be party mode. Use the player party's location as the
1499 x = player_party->getX();
1500 y = player_party->getY();
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
1505 if (player_party->get_num_living_members() == 1) {
1506 pc = player_party->get_first_living_member();
1507 cmdwin_spush("%s", pc->getName());
1509 pc = select_party_member();
1516 // *** Pick a target ***
1518 if (select_target(x, y, &x, &y, 1, 0) == -1)
1521 // Try to find a mech
1523 mech = place_get_object(Place, x, y, mech_layer);
1525 || ! mech->getObjectType()->canHandle()
1526 || (! mech->isVisible()
1528 cmdwin_spush("²¿¤â¤Ê¤¤¡ª");
1529 log_msg("Áàºî¤¹¤ë - ²¿¤â¤Ê¤¤¡ª");
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();
1537 mechName = "±£¤µ¤ì¤¿ÁõÃÖ";
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"));
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
1549 //player_party->updateView();
1554 bool cmdUse(class Character * member, int flags)
1556 struct inv_entry *ie;
1557 class ObjectType *item;
1561 cmdwin_spush("»È¤¦");
1564 if (flags & CMD_SELECT_MEMBER) {
1565 member = select_party_member();
1570 cmdwin_spush("%s", member->getName());
1572 statusSelectCharacter(member->getOrder());
1574 // select item to use
1576 ie = ui_select_item();
1577 statusSetMode(ShowParty);
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);
1590 assert(item->isUsable());
1593 log_begin("%s: %s - ", member->getName(), item->getName());
1594 result = item->use(member);
1595 cmd_eval_and_log_result(result);
1598 member->runHook(OBJ_HOOK_USE_DONE, "p", item);
1600 // Item's appear to decrement AP in the script...
1601 //member->decActionPoints(kern_intvar_get("AP_COST:use_item"));
1607 /* Helper function called by cmdNewOrder: */
1608 static void cmd_switch_party_leader(class Character *old_leader,
1609 class Character *new_leader)
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);
1618 void cmdNewOrder(void)
1620 class Character *pc1, *pc2;
1622 switch (player_party->getSize()) {
1627 log_msg("½ç½ø - ¤¢¤Ê¤¿¤·¤«¤¤¤Ê¤¤¡ª");
1630 pc1 = player_party->getMemberByOrder(0);
1631 pc2 = player_party->getMemberByOrder(1);
1636 cmdwin_spush("Æþ¤ìÂؤï¤ë");
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);
1643 pc1 = select_party_member();
1645 statusSetMode(ShowParty);
1651 pc2 = select_party_member();
1653 statusSetMode(ShowParty);
1657 statusSetMode(ShowParty);
1659 player_party->switchOrder(pc1, pc2);
1661 log_msg("½ç½ø: %s¤Ï%s¤ÈÆþ¤ìÂؤï¤Ã¤¿¡£", pc1->getName(),
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);
1676 static void run_combat(bool camping, class Character * guard, int hours,
1679 struct move_info minfo;
1680 struct combat_info cinfo;
1682 assert(!foe || foe->isType(PARTY_ID));
1684 memset(&minfo, 0, sizeof(minfo));
1685 minfo.place = Place;
1686 minfo.x = player_party->getX();
1687 minfo.y = player_party->getY();
1690 minfo.npc_party = (class Party*)foe;
1692 memset(&cinfo, 0, sizeof(cinfo));
1693 cinfo.camping = camping;
1694 cinfo.guard = guard;
1695 cinfo.hours = hours;
1696 cinfo.move = &minfo;
1698 // Is there an enemy?
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
1705 cinfo.defend = true;
1706 place_get_direction_vector(minfo.place,
1707 foe->getX(), foe->getY(),
1709 &minfo.dx, &minfo.dy);
1711 // No, so we're camping or zooming in. Party values are fine
1713 minfo.dx = player_party->getDx();
1714 minfo.dy = player_party->getDy();
1717 combat_enter(&cinfo);
1721 class Object *origin;
1722 class Object *nearest;
1725 struct list suggest;
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
1731 static void cmd_talk_info_visitor(class Object *obj, void *data)
1733 struct location_list *entry = 0;
1735 struct talk_info *info =
1736 (struct talk_info*)data;
1738 if (! obj->getConversation())
1741 if (obj->isPlayerControlled())
1747 if (! obj->isVisible() && ! Reveal)
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(),
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(),
1767 if (dist > info->range)
1770 /* Add this conversant to the suggestion list. */
1771 entry = (struct location_list*)malloc(sizeof(*entry));
1773 entry->x = obj->getX();
1774 entry->y = obj->getY();
1775 list_add_tail(&info->suggest, &entry->list);
1777 /* Remember the nearest conversant. */
1779 || dist < info->min_distance) {
1780 info->nearest = obj;
1781 info->min_distance = dist;
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,
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);
1798 place_for_each_object(member->getPlace(),
1799 cmd_talk_info_visitor,
1802 return info->nearest;
1805 /* cmd_cleanup_talk_info - free the 'suggest' list. */
1806 static void cmd_cleanup_talk_info(struct talk_info *info)
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);
1817 void cmdTalk(Object *member)
1819 struct conv *conv = NULL;
1820 class Object *obj, *conversant = NULL;
1822 struct talk_info info;
1823 const int max_distance = 5;
1825 // *** Prompt user & check if valid ***
1828 cmdwin_spush("Ïä¹");
1831 member = select_party_member();
1836 // start cursor on nearest object with a conversation
1837 conversant = cmd_get_talk_info(&info, member, max_distance);
1839 conversant = member;
1842 x = conversant->getX();
1843 y = conversant->getY();
1845 if (select_target(member->getX(), member->getY(),
1846 &x, &y, max_distance, &info.suggest) == -1) {
1850 obj = place_get_object(Place, x, y, being_layer);
1853 cmdwin_spush("ï¤â¤¤¤Ê¤¤¡ª");
1854 log_msg("¿Í¤ÈÏ乤褦¤Ë¡ª");
1858 // This next bit was added to support talking to parties, where the
1859 // speaker is not the party itself.
1860 obj = obj->getSpeaker();
1862 cmdwin_spush("̾ȧ");
1866 if (TimeStop && !obj->isPlayerPartyMember()) {
1867 cmdwin_spush("»þ¤¬»ß¤Þ¤Ã¤Æ¤¤¤ë¡ª");
1868 log_msg("¤³¤Î¿Í¤Ï¤Þ¤ë¤ÇÅà¤Ã¤Æ¤¤¤ë¤è¤¦¤À¡£");
1872 conv = obj->getConversation();
1874 cmdwin_spush("È¿±þ¤¬¤Ê¤¤¡ª");
1877 log_end("¤«¤é¤Ï²¿¤ÎÈ¿±þ¤â¤Ê¤«¤Ã¤¿¡£");
1881 cmdwin_spush(obj->getName());
1883 if (((obj->getLayer() == being_layer)
1884 && ((class Character*)obj)->isAsleep())) {
1885 log_msg("Zzzz...\n");
1889 conv_enter(obj, member, conv);
1894 cmd_cleanup_talk_info(&info);
1899 bool cmdZtats(class Character * pc)
1901 statusRunApplet(ztats_get_applet()); /* runs until user ESC */
1902 statusSetMode(ShowParty); /* restore default status mode */
1906 static int select_hours(int allow_sunrise)
1908 struct get_char_info info;
1910 if (allow_sunrise) {
1911 cmdwin_spush("<[0-9]»þ´Ö/[s]ÌëÌÀ¤±>");
1912 info.string = "0123456789sS";
1914 cmdwin_spush("<[0-9]»þ´Ö>");
1915 info.string = "0123456789";
1920 getkey(&info, &cmd_getchar);
1922 if (! info.c || info.c == '0') {
1924 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1927 else if (allow_sunrise
1928 && (info.c == 's' ||
1934 cmdwin_push("ÌëÌÀ¤±¤Þ¤Ç");
1935 hour = clock_time_of_day() / 60;
1936 sunrise = SUNRISE_HOUR + 1;
1938 return sunrise - hour;
1939 return HOURS_PER_DAY - hour + sunrise;
1941 else if (info.c == '1') {
1942 cmdwin_push("»þ´Ö");
1946 cmdwin_push("»þ´Ö");
1947 return info.c - '0';
1951 int ui_get_quantity(int max)
1953 struct get_number_info info;
1956 /* Push the prompt but remember it for use within getnum() */
1958 snprintf(prompt, sizeof(prompt), "<¿ôÎÌ>");
1960 snprintf(prompt, sizeof(prompt),
1961 "<¿ôÎÌ[0-%d]/ENT=%d>", max, max);
1965 info.state = GN_ALL;
1966 info.prompt = prompt;
1968 cmdwin_spush(info.prompt);
1969 getkey(&info, getnum);
1971 if (info.state == GN_ALL) {
1976 } else if (info.state == GN_CANCEL) {
1977 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
1983 int cmd_camp_in_wilderness(class Party *camper)
1986 class Character *guard = 0;
1989 cmdwin_spush("µÙ©¤ò¼è¤ë");
1991 if (!place_is_passable(camper->getPlace(), camper->getX(),
1992 camper->getY(), camper, PFLAG_IGNOREVEHICLES)) {
1993 cmdwin_spush("¤³¤³¤Ç¤Ï¤Ç¤¤Ê¤¤¡ª");
1994 log_msg("µÙ©¤ò¼è¤ë - ¤³¤³¤Ç¤Ï¤Ç¤¤Ê¤¤¡ª");
1998 if (place_get_subplace(camper->getPlace(),
2001 cmdwin_spush("¤³¤³¤Ç¤Ï¤Ç¤¤Ê¤¤¡ª");
2002 log_msg("µÙ©¤ò¼è¤ë - ¤³¤³¤Ç¤Ï¤Ç¤¤Ê¤¤¡ª");
2006 hours = select_hours(1);
2010 cmdwin_spush(""); /* for the '-' */
2011 cmdwin_spush("¸«Ä¥¤ê¤òÃÖ¤¯");
2012 cmdwin_spush("<y/n>");
2013 getkey(&yesno, &yesnokey);
2018 guard = select_party_member();
2021 cmdwin_push("¸«Ä¥¤ê¤Ê¤·");
2023 else if (guard->isDead()) {
2024 log_msg("°äÂΤòΩ¤Æ¤«¤±¡¢Çè¤òʧ¤¤¤Î¤±¤¿¡Ä");
2026 // else select_party_member() prints the name
2030 cmdwin_spush("¸«Ä¥¤ê¤Ê¤·");
2033 player_party->beginCamping(guard, hours);
2035 run_combat(true, guard, hours, NULL);
2040 void cmdLoiter(class Being *subject)
2045 cmdwin_spush("¤¦¤í¤Ä¤¯");
2047 /* Check if enemies are around. */
2048 if (place_contains_hostiles(subject->getPlace(), subject)) {
2049 cmdwin_spush("Ũ¤¬¶á¤¯¤Ë¤¤¤ë¡ª");
2050 log_msg("¤¦¤í¤Ä¤¯ - Ũ¤¬¶á¤¯¤Ë¤¤¤ë¡ª");
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("Ë»¤·¤¤¡ª");
2062 /* Prompt for the number of hours. */
2063 hours = select_hours(0);
2068 /* Tell the party to start loitering. */
2069 cmdwin_spush("¤¦¤í¤Ä¤¤¤Æ¤¤¤ë¡Ä");
2070 player_party->beginLoitering(hours);
2077 int cmd_camp_in_town(class Character *camper)
2082 cmdwin_spush("µÙ©¤ò¼è¤ë");
2084 // Party must be in follow mode.
2085 if (player_party->getPartyControlMode() != PARTY_CONTROL_FOLLOW) {
2086 cmdwin_spush("must be in follow mode!");
2088 log_msg("µÙ©¤ò¼è¤ë - ÄÉÀ×Ãæ¤Ç¤Ê¤¤¡ª");
2089 log_msg("¥Ò¥ó¥È: 'f'¤ò²¡¤¹¤ÈÄÉÀפ¹¤ë¡£");
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("µÙ©¤ò¼è¤ë - ¥Ù¥Ã¥É¤¬¤Ê¤¤¡ª");
2102 // Rendezvous the party around the bed.
2103 if (! player_party->rendezvous(camper->getPlace(), camper->getX(),
2105 log_msg("µÙ©¤ò¼è¤ë - Ãç´Ö¤È½¸¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2109 // Prompt for the number of hours to sleep.
2110 hours = select_hours(! camper->getPlace()->underground);
2114 // Put the party in "sleep" mode before returning back to the main
2116 cmdwin_spush("µÙ©Ãæ¡Ä");
2117 player_party->beginResting(hours);
2120 return TURNS_PER_HOUR;
2123 int get_spell_name(struct KeyHandler *kh, int key, int keymod)
2125 struct get_spell_name_data *ctx;
2128 ctx = (struct get_spell_name_data *) kh->data;
2130 switch (ctx->state) {
2132 case GN_ZERO: /* No spell words are entered yet and the prompt is
2142 if (key == CANCEL) {
2144 ctx->spell_name[0] = 0;
2151 /* Lookup the word that goes with the letter. */
2152 letter = toupper(key);
2153 word = magic_lookup_word(&Session->magic, letter);
2158 /* Clear prompt, show the word and advance. */
2164 ctx->state = GN_SOME;
2169 case GN_SOME: /* One or more words are already entered. */
2171 /* Done? Ensure null-termination. */
2173 /* Segment-push a null string to force a '-' following
2174 * the spell name. */
2180 /* Abort? Terminate string at beginning. */
2181 if (key == CANCEL) {
2182 ctx->spell_name[0] = 0;
2187 if (key == '\b' && ctx->n) {
2193 /* Back to empty? Re-prompt. */
2195 cmdwin_spush(ctx->prompt);
2196 ctx->state = GN_ZERO;
2202 if (ctx->n == MAX_WORDS_IN_SPELL_NAME) {
2210 /* Lookup the word that goes with the letter. */
2211 letter = toupper(key);
2212 word = magic_lookup_word(&Session->magic, letter);
2217 /* Accept the word and print it. After the first word separate words
2219 cmdwin_push(" %s", word);
2225 default: /* Invalid state */
2232 int select_spell(struct get_spell_name_data *context)
2234 struct KeyHandler kh;
2236 memset(context, 0, sizeof(*context));
2237 context->ptr = context->spell_name;
2238 context->prompt = "<¼öʸ>";
2239 context->state = GN_ZERO;
2241 kh.fx = get_spell_name;
2244 cmdwin_spush(context->prompt);
2245 eventPushKeyHandler(&kh);
2247 eventPopKeyHandler();
2249 if (strlen(context->spell_name) == 0) {
2250 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
2258 * Log console messages describing the results of a closure call and return
2259 * whether or not it succeeded.
2261 * @param result is what closure_exec() returned. It should be one of the
2262 * standard result codes.
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.
2269 static int cmd_eval_and_log_result(int result)
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 },
2286 if (result < 0 || result >= array_sz(tbl)) {
2287 warn("result code '%d' unknown\n", result);
2291 log_continue(tbl[result].string);
2292 return tbl[result].success;
2295 bool cmdCastSpell(class Character * pc)
2297 struct get_spell_name_data context;
2298 struct inv_entry *ie = NULL;
2299 struct spell *spell;
2301 bool natural = false;
2302 int i, cast = 0, result = 0;
2303 char spell_name[MAX_SPELL_NAME_LENGTH];
2306 log_msg("¾§¤¨¤ë - ÂǤÁ¾Ã¤µ¤ì¤¿¡ª\n");
2311 cmdwin_spush("¾§¤¨¤ë");
2313 /* If the pc is null then we are in non-combat mode and need to promp
2316 pc = select_party_member();
2320 statusSetMode(ShowParty);
2323 /* Make sure the PC is not asleep, dead, etc. */
2325 cmdwin_spush("º£¤Ï¤Ç¤¤Ê¤¤¡ª");
2326 log_msg("¾§¤¨¤ë - %s¤Ï»à¤ó¤Ç¤¤¤ë¡ª", pc->getName());
2330 if (pc->isAsleep()) {
2331 cmdwin_spush("º£¤Ï¤Ç¤¤Ê¤¤¡ª");
2332 log_msg("¾§¤¨¤ë - %s¤Ï̲¤Ã¤Æ¤¤¤ë¡ª", pc->getName());
2336 /* Prompt to select a spell */
2337 if (select_spell(&context) == -1)
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);
2346 log_begin("%s: %s - ", pc->getName(), spell_name);
2348 /* Lookup the spell in the list of valid spells. */
2349 spell = magic_lookup_spell(&Session->magic, context.spell_name);
2351 /* Bugfix for SF1564255: don't let player guess at spells. */
2352 cmdwin_spush("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2353 log_end("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2357 /* Check if the spell can be used in this context. */
2358 if (!(player_party->getContext() & spell->context)) {
2359 cmdwin_spush("¤³¤³¤Ç¤Ï»È¤¨¤Ê¤¤¡ª");
2360 log_end("¤³¤³¤Ç¤Ï»È¤¨¤Ê¤¤¡ª");
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)) {
2372 /* Check if the caster is of sufficient level. */
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...
2377 if (!natural && pc->getLevel() < spell->level) {
2378 cmdwin_spush("¤â¤Ã¤È·Ð¸³¤¬É¬Íסª");
2379 log_end("¥ì¥Ù¥ë%d°Ê¾åɬÍפÀ¡ª", spell->level);
2383 /* Check party inventory for a mixed spell. */
2385 ie = player_party->inventory->search(spell->type);
2386 if (ie && ie->count)
2390 if (!natural && !mixed) {
2391 cmdwin_spush("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2392 log_end("Ä´¹ç¤·¤Æ¤¤¤Ê¤¤¡ª");
2396 /* Check if the character has enough mana to cast the spell. */
2397 if (pc->getMana() < spell->cost) {
2398 cmdwin_spush("¤â¤Ã¤ÈËâÎϤ¬É¬Íסª");
2399 log_end("¤â¤Ã¤ÈËâÎϤ¬É¬ÍפÀ¡ª");
2403 /* Cast the spell. */
2404 result = spell->type->cast(pc);
2405 cast = cmd_eval_and_log_result(result);
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);
2418 /* If the spell was mixed then remove it from inventory. */
2420 int count = ie->count - 1;
2421 player_party->takeOut(ie->type, 1);
2423 log_msg("¸å%d²ó»Ä¤Ã¤Æ¤¤¤ë¡£", count);
2425 log_msg("¤â¤¦»Ä¤Ã¤Æ¤¤¤Ê¤¤¡£");
2429 /* Some spells have status in the foogod window, so repaint it now. */
2438 bool cmdMixReagents(class Character *character)
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];
2448 list_init(&reagents);
2451 cmdwin_spush("Ä´¹ç¤¹¤ë");
2453 // Select a spell...
2454 if (select_spell(&context) == -1)
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);
2463 // Lookup the spell. If null then keep going and bomb when done.
2464 spell = magic_lookup_spell(&Session->magic, context.spell_name);
2466 // Show the player how many he already has mixed...
2469 ie_spell = player_party->inventory->search(spell->type);
2471 if (ie_spell && ie_spell->count) {
2472 cmdwin_spush("%d¤ÄÄ´¹ç¤µ¤ì¤Æ¤¤¤ë", ie_spell->count);
2474 cmdwin_spush("Ä´¹ç¤µ¤ì¤Æ¤¤¤Ê¤¤");
2477 // Prompt for reagents
2478 cmdwin_spush("<ÁªÂò¤·¤¿¸å'm'¤ÇÄ´¹ç>");
2480 foogodSetHintText("\005\006=ÁªÂò ENT=²Ã¤¨¤ë/¼è¤ê½ü¤¯ ESC=ÃæÃÇ M=Ä´¹ç");
2481 foogodSetMode(FOOGOD_HINT);
2483 // Show the reagents in the status window
2484 statusSetMode(MixReagents);
2486 struct ScrollerContext sc;
2487 sc.selector = Reagents;
2492 struct KeyHandler kh;
2496 eventPushKeyHandler(&kh);
2499 sc.selection = NULL;
2503 // u5 silently aborts here
2505 eventPopKeyHandler();
2506 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
2513 ie = (struct inv_entry *) sc.selection;
2515 /* This happens when the player has no reagents
2518 eventPopKeyHandler();
2519 cmdwin_spush("¤Ê¤Ë¤â¤·¤Ê¤¤¡ª");
2526 list_remove(&ie->auxlist);
2530 list_add(&reagents, &ie->auxlist);
2537 eventPopKeyHandler();
2539 if (list_empty(&reagents)) {
2540 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
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;
2553 // Prompt for the number of mixtures to make
2559 quantity = ui_get_quantity(max_quantity);
2561 if (quantity == 0) {
2565 if (quantity <= max_quantity)
2568 cmdwin_spush(0); /* for the '-' after the quantity */
2569 cmdwin_spush("ÈëÌô¤¬Â¤ê¤Ê¤¤¡ª");
2570 getkey(&dummy, anykey);
2571 cmdwin_pop_to_mark();
2575 log_begin("Ä´¹ç¤¹¤ë: %s - ", spell_name);
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.
2582 for (int i = 0; i < spell->n_reagents; i++) {
2584 list_for_each(&reagents, elem) {
2585 ie = outcast(elem, struct inv_entry, auxlist);
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!
2593 player_party->takeOut(ie->type,
2604 // Now, if any reagents remain leftover then remember this fact and
2605 // remove the remaining reagents from inventory.
2606 if (!list_empty(&reagents)) {
2608 elem = reagents.next;
2609 while (elem != &reagents) {
2610 struct list *tmp = elem->next;
2611 ie = outcast(elem, struct inv_entry, auxlist);
2615 player_party->takeOut(ie->type, quantity);
2619 statusSetMode(ShowParty);
2620 foogodSetMode(FOOGOD_DEFAULT);
2622 // committed to action now, so decrement AP
2624 character->runHook(OBJ_HOOK_MIX_DONE, 0);
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)
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)
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
2658 // If the spell is invalid or the reagents are incorrect then punish
2661 cmdwin_spush("¤ª¤ª¤Ã¤È¡ª");
2662 player_party->damage(DAMAGE_ACID);
2666 } else if (mistake) {
2667 cmdwin_spush("¤¦¤ï¤¢¤Ã¡ª");
2668 player_party->damage(DAMAGE_BOMB);
2673 // All is well. Add the spell to player inventory.
2674 cmdwin_spush("À®¸ù");
2675 player_party->add(spell->type, quantity);
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);
2688 statusSetMode(ShowParty);
2689 foogodSetMode(FOOGOD_DEFAULT);
2693 void look_at_XY(struct place *place, int x, int y, void *unused)
2695 if (DeveloperMode) {
2696 log_begin("At XY=(%d,%d): ", x, y);
2701 if ( mapTileIsVisible(x, y) ) {
2702 if (mapTileLightLevel(x,y) < MIN_XAMINE_LIGHT_LEVEL) {
2703 log_continue("°Å¤¹¤®¤ë¡ª");
2705 place_describe(place, x, y, PLACE_DESCRIBE_ALL);
2706 log_continue("¤¬¸«¤¨¤ë¡£");
2708 } else if (ShowAllTerrain || XrayVision) {
2709 place_describe(place, x, y, PLACE_DESCRIBE_TERRAIN);
2710 log_continue("¤¬Æ©»ë¤Ç¤¤ë¡£");
2712 log_continue("¸«¤¨¤Ê¤¤¡ª");
2718 int detailed_examine_XY(struct place *place, int x, int y, void *unused)
2720 if (DeveloperMode) {
2721 log_begin("At XY=(%d,%d): ", x, y);
2726 if ( mapTileIsVisible(x, y) ) {
2727 if (mapTileLightLevel(x,y) < MIN_XAMINE_LIGHT_LEVEL) {
2728 log_continue("¸«¤¨¤Ê¤¤¡ª");
2730 log_continue("¼¡¤Î¤â¤Î¤¬¸«¤¨¤ë¡£\n");
2731 place_examine(place, x, y);
2733 } else if (ShowAllTerrain || XrayVision) {
2734 log_continue("¼¡¤Î¤â¤Î¤¬Æ©»ë¤Ç¸«¤¨¤ë¡£\n");
2735 place_examine(place, x, y);
2737 log_continue("¸«¤¨¤Ê¤¤¡ª");
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
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
2755 // o information specific to the object type, such as:
2756 // o Triggers: current state, and perhaps what it is
2758 // o NpcParties: faction, movement mode
2760 // o Vehicles: movement mode, armament, current HP
2761 // o Portable items: weapon/armor stats, (U)se effects,
2763 // Hmmm...what else?
2766 log_msg("DETAIL XY=(%d,%d) out of LOS\n", x, y);
2771 return 0; /* keep on targeting */
2774 bool cmdXamine(class Object * pc)
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...
2783 cmdwin_spush("Ä´¤Ù¤ë");
2791 log_msg("%s¤Ï¤¢¤¿¤ê¤òÄ´¤Ù¤¿¡Ä", pc->getName());
2793 log_msg("¤¢¤Ê¤¿¤Ï¤¢¤¿¤ê¤òÄ´¤Ù¤¿¡Ä");
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) {
2806 const char * name_of_context (void)
2808 // SAM: Perhaps this function belongs in common.c?
2809 switch (player_party->getContext()) {
2810 case CONTEXT_WILDERNESS:
2811 return "Á´°÷¤Î¾õÂÖ";
2814 return "¸Ä¿Í¤Î¾õÂÖ";
2817 } // name_of_context()
2819 bool cmdAT (class Character * pc)
2822 const char * who = "";
2823 const char * place_name = "";
2827 // Should I check player_party->context
2828 // for the context info below,
2829 // rather than the current method?
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;
2839 // Must be party mode.
2840 // Use the player party's location as the origin.
2842 place_name = player_party->getPlace()->name;
2843 x = player_party->getX();
2844 y = player_party->getY();
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;
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() );
2858 log_msg("º£¤Ï%dǯ %s %s "
2860 Session->clock.year, month_name(), week_name(),
2861 day_name(), vague_time_as_string() );
2863 // SAM: Is this really interesting though, I wonder?
2864 log_msg("%d²ó¤¬·Ð²á¤·¤¿¡£", Turn);
2866 log_msg("É÷¤Ï%s¤«¤é¿á¤¤¤Æ¤¤¤ë¡£",
2867 directionToString(windGetDirection()) );
2869 if (Place->underground) {
2870 log_msg("%s¤ÏÃϲ¼¤Ë¤¤¤Æ¶õ¤Ï¸«¤¨¤Ê¤¤¡£",
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);
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
2888 log_msg("Æü¤¬¾º¤Ã¤Æ¤¤¤ë¡£");
2889 } else if (is_midnight()) {
2890 log_msg("Æü¤ÏÄÀ¤ó¤Ç¤¤¤ë¡£");
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,
2900 if (body->n_phases > 1) {
2902 body->phases[body->phase].
2905 log_continue("¡¢%s",
2908 log_continue("¡¢·îÁê¤Ï%d",
2916 } // open air, under the sky
2918 if (player_party->getVehicle()) {
2919 log_msg("%s¤Ï%s¤Ë¾è¤Ã¤Æ¤¤¤ë¡£",
2920 who, player_party->getVehicle()->getName() );
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.
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);
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.
2958 * cmd_terraform - edit terrain interactively
2960 bool cmd_terraform(struct place *place, int x, int y)
2962 terrain_editor_run(place, x, y);
2966 bool cmd_save_current_place (struct place * place)
2969 const char * file_path;
2973 //log_msg("cmd_save_current_place");
2974 //printf("cmd_save_current_place()\n");
2976 file_path = "_test_save_place";
2978 file = file_open_in_save_dir(file_path, "w");
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));
2984 Session->session_id++; // Must increment to cause saving.
2986 save = save_new(file);
2988 save->session_id = Session->session_id;
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);
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...
3009 void cmdZoomIn(void)
3011 struct place *subplace = 0;
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...
3017 // For now, I print a placeholder message for each case here:
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
3026 log_msg("Æþ¤ë-%s", subplace->name);
3027 player_party->try_to_enter_subplace_from_edge(subplace,
3030 log_msg("Æþ¤ë-Æþ¤ê¸ý¤«¤éÆþ¤Ã¤¿¡ª");
3033 } else if (!place_is_passable(player_party->getPlace(),
3034 player_party->getX(),
3035 player_party->getY(),
3037 PFLAG_IGNOREVEHICLES)) {
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,
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);
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);
3064 class Character *pc;
3065 if ((pc = cmdAnyPartyMemberEngagedInTask())) {
3066 log_msg("µñÈÝ - %s¤ÏÊ̤Τ³¤È¤ò¤·¤Æ¤¤¤ë¡ª", pc->getName());
3067 cmdwin_spush("busy with tasks!");
3071 char *fname = save_game_menu();
3073 cmdwin_spush("Ãæ»ß¡ª");
3077 log_begin("%s¤ËÊݸÃæ¡Ä", fname);
3078 if (session_save(fname)) {
3079 log_end("^c+r¼ºÇÔ¡ª^c-");
3080 cmdwin_spush("¼ºÇÔ¡ª");
3083 cmdwin_spush("ok!");
3084 log_end("^c+g´°Î»¡ª^c-");
3086 session_save(fname);
3091 void cmdReload(void)
3096 /****** New UI ******/
3101 int ui_get_yes_no(const char *name)
3105 cmdwin_spush("ÊÖÅú");
3106 cmdwin_spush("<y/n>");
3107 getkey(&yesno, yesnokey);
3110 cmdwin_spush("¤Ï¤¤");
3111 log_msg("^c+%c%s:^c- ¤Ï¤¤", CONV_PC_COLOR, name);
3114 cmdwin_spush("¤¤¤¤¤¨");
3115 log_msg("^c+%c%s:^c- ¤¤¤¤¤¨", CONV_PC_COLOR, name);
3120 typedef struct ui_getline_data {
3124 int (*filter)(int key);
3127 static int ui_getline_handler(struct KeyHandler *kh, int key, int keymod)
3129 getline_t *data = (getline_t*)kh->data;
3134 if (key == CANCEL) {
3135 while (data->ptr > data->buf) {
3141 alpha_to_kana(0, NULL);
3146 alpha_to_kana(0, NULL);
3151 if (data->ptr != data->buf) {
3152 if (*(data->ptr - 1) & 0x80) {
3165 alpha_to_kana(0, NULL);
3170 && data->filter(key)) {
3171 alpha_to_kana(0, NULL);
3175 if ((isprintable(key) || (key & 0x80))
3177 cmdwin_push("%c", key);
3182 kana_len = alpha_to_kana (key, kana_buf);
3184 for (i = 0; i < kana_len; i++) {
3185 ui_getline_handler (kh, kana_buf[i], keymod);
3192 int ui_getline_filtered(char *buf, int len, int (*filter)(int key))
3194 struct KeyHandler kh;
3199 data.room = len - 1;
3200 data.filter = filter;
3202 memset(buf, 0, len);
3204 kh.fx = ui_getline_handler;
3207 eventPushKeyHandler(&kh);
3209 eventPopKeyHandler();
3211 return len - (data.room + 1);
3214 int ui_getline_plain(char *buf, int len)
3216 return ui_getline_filtered(buf, len, 0);
3219 int ui_getline(char *buf, int len)
3222 cmdwin_push("¸À¤¦: ");
3223 return ui_getline_plain(buf, len);
3226 int ui_buy(struct merchant *merch)
3228 struct KeyHandler kh;
3229 struct ScrollerContext sc;
3230 struct trade_info *trade;
3231 int quantity, cost, max_q, bought = 0;
3233 statusSetTradeInfo(merch->n_trades, merch->trades);
3234 statusSetMode(Trade);
3236 sc.selector = TradeItem;
3242 // *** selection ***
3244 sc.selection = NULL;
3247 cmdwin_spush("Ç㤦");
3248 cmdwin_spush("<ÁªÂò/ESC>");
3249 eventPushKeyHandler(&kh);
3251 eventPopKeyHandler();
3254 trade = (struct trade_info *) sc.selection;
3257 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
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);
3267 cmdwin_spush("%s", trade->name);
3269 if (player_party->gold < trade->cost) {
3271 cmdwin_spush("¶â²ß¤¬Â¤ê¤Ê¤¤¡ª <¥¡¼¤ò²¡¤¹>");
3272 getkey(&dummy, anykey);
3278 max_q = player_party->gold / trade->cost;
3279 quantity = ui_get_quantity(max_q);
3280 cmdwin_pop_to_mark();
3282 if (quantity == 0) {
3283 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3287 quantity = min(quantity, max_q);
3288 cmdwin_spush("%d", quantity);
3290 cost = quantity * trade->cost;
3294 class ObjectType *type = (class ObjectType*)trade->data;
3295 cmdwin_spush("Çã¤Ã¤¿");
3296 log_msg("¤¢¤Ê¤¿¤Ï%s¤ò¶â²ß%dËç¤Ç%d¤ÄÇã¤Ã¤¿¡£\n", trade->name,
3299 player_party->gold -= cost;
3300 if (type->canBuy()) {
3301 type->buy(player_party->get_leader(), quantity);
3303 player_party->add(type, quantity);
3305 trade->quantity = player_party->inventory->numAvail(type);
3311 statusSetMode(ShowParty);
3315 static bool conv_filter_trade(struct inv_entry *ie, void *fdata)
3317 struct trade_info *trade = (struct trade_info*)fdata;
3318 return (ie->type == trade->data && ie->count > ie->ref);
3321 static int fill_sell_list(struct merchant *merch, struct trade_info *trades)
3323 struct inv_entry *ie = NULL;
3324 struct filter filter;
3327 filter.fx = conv_filter_trade;
3329 for (i = 0; i < merch->n_trades; i++) {
3331 if (merch->trades[i].cost / MARKUP == 0)
3334 filter.fdata = &merch->trades[i];
3335 ie = player_party->inventory->first(&filter);
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;
3350 int ui_sell(struct merchant *merch)
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
3360 struct trade_info *trades;
3361 struct KeyHandler kh;
3362 struct ScrollerContext sc;
3363 struct trade_info *trade;
3366 // Allocate the trade list.
3367 trades = new struct trade_info[merch->n_trades];
3369 log_msg("^c+%c%s:^c- ¤½¤ì¤Ï¤¤¤é¤Ê¤¤¡£\n",
3370 CONV_NPC_COLOR, merch->name);
3373 // Fill out the list
3374 n_trades = fill_sell_list(merch, trades);
3375 statusSetTradeInfo(n_trades, trades);
3376 statusSetMode(Trade);
3378 sc.selector = TradeItem;
3384 struct inv_entry *ie;
3385 int quantity, max_q;
3387 sc.selection = NULL;
3390 cmdwin_spush("Çä¤ë");
3391 cmdwin_spush("<ÁªÂò/ESC>");
3392 eventPushKeyHandler(&kh);
3394 eventPopKeyHandler();
3397 trade = (struct trade_info *) sc.selection;
3400 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3404 cmdwin_spush("%s", trade->name);
3406 ie = player_party->inventory->search((class ObjectType *)
3409 assert(ie->ref < ie->count);
3413 max_q = ie->count - ie->ref;
3416 quantity = ui_get_quantity(max_q);
3417 cmdwin_pop_to_mark();
3419 if (quantity == 0) {
3420 cmdwin_spush("²¿¤â¤·¤Ê¤¤¡ª");
3424 quantity = min(quantity, max_q);
3425 cmdwin_spush("%d", quantity);
3428 player_party->takeOut(ie->type, quantity);
3429 player_party->gold += quantity * trade->cost;
3433 log_msg("¤¢¤Ê¤¿¤Ï%s¤ò¶â²ß%dËç¤Ç%d¤ÄÇä¤Ã¤¿¡£\n", trade->name,
3434 quantity * trade->cost, quantity);
3436 // refresh the sell list
3437 n_trades = fill_sell_list(merch, trades);
3438 statusSetTradeInfo(n_trades, trades);
3439 statusUpdateTradeInfo(n_trades, trades);
3443 statusSetMode(ShowParty);
3449 static int get_buy_or_sell_key(struct KeyHandler *kh, int key, int keymod)
3451 int *val = (int *) kh->data;
3470 int ui_trade(struct merchant *merch)
3472 int key, traded = 0;
3476 cmdwin_spush("Ç㤦/Çä¤ë¡©");
3477 cmdwin_spush("<B:Ç㤦/S:Çä¤ë/ESC>");
3478 getkey(&key, get_buy_or_sell_key);
3482 traded += ui_buy(merch);
3485 traded += ui_sell(merch);
3489 cmdwin_spush("none!");
3495 static const char *cmd_help_text =
3496 "Êý¸þ¤ÏÌð°õ¥¡¼(¥Æ¥ó¥¡¼)¤Ç¼¨¤¹¡£\n"
3497 "ESC¤ò²¡¤¹¤ÈÌ¿Îá¤òÃæÃǤ¹¤ë¡£\n"
3498 "Ì¿Îá¤Ï¼¡¤ÎÄ̤ê¤Ç¤¢¤ë¡£\n"
3500 "A)²¿¤«¤ò¹¶·â¤¹¤ë\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"
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"
3528 "²ñÏÃÃæ¤Ï¥¡¼¥ï¡¼¥É¤òÆþÎϤ¹¤ë¡£Â¿¤¯¤Î¿Íʪ¤Ï¡¢\n"
3529 "̾Á°¡¢»Å»ö¡¢¼è°ú¡¢Ãç´Ö¤ËÂФ·¤ÆÈ¿±þ¤¹¤ë¡£¤³¤¿\n"
3530 "¤¨¤Ë¤Ï¹¹¤Ê¤ë¥¡¼¥ï¡¼¥É¤Î¼ê¤¬¤«¤ê¤¬´Þ¤Þ¤ì¤Æ¤¤\n"
3536 struct KeyHandler kh;
3538 foogodSetHintText(PAGER_HINT);
3539 foogodSetMode(FOOGOD_HINT);
3540 statusSetPageText("Ì¿Îá", cmd_help_text);
3541 statusSetMode(Page);
3545 eventPushKeyHandler(&kh);
3547 eventPopKeyHandler();
3549 statusSetMode(ShowParty);
3550 foogodSetMode(FOOGOD_DEFAULT);
3553 void ui_name_vehicle(class Vehicle *vehicle)
3558 log_begin("¤¢¤Ê¤¿¤Î");
3559 vehicle->describe();
3560 log_end("¤Ë̾Á°¤ò¤Ä¤±¤ë¤«¡©");
3561 cmdwin_spush("̾¤Å¤±¤ë");
3563 cmdwin_spush("<y/n>");
3564 getkey(&yesno, yesnokey);
3569 cmdwin_spush("¤¤¤¤¤¨¡ª");
3570 log_msg("¤Þ¤ë¤ÇÅð¤ó¤À¤â¤Î¤Î¤è¤¦¤À¡ª");
3574 if (!ui_getline(buf, sizeof(buf))) {
3575 log_msg("¤Þ¤ë¤ÇÅð¤ó¤À¤â¤Î¤Î¤è¤¦¤À¡ª");
3579 vehicle->setName(buf);
3581 log_begin("¤¢¤Ê¤¿¤Ï");
3582 vehicle->describe();
3583 log_end("¤È̾¤Å¤±¤¿¡£");
3586 void cmdSettings(void)
3588 StatusMode omode = statusGetMode();
3590 statusSetMode(omode);
3593 void cmdDrop(class Character *actor)
3595 enum StatusMode omode;
3596 struct inv_entry *ie;
3598 int maxq, quantity, dir, x, y;
3603 cmdwin_spush("ÃÖ¤¯");
3605 omode = statusGetMode();
3606 statusBrowseContainer(actor->getInventoryContainer(), "ÃÖ¤¯");
3607 ie = ui_select_item();
3608 statusSetMode(omode);
3614 maxq = ie->count - ie->ref;
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());
3625 /* prompt for a count (unless there is only one) */
3626 if (ie->count == 1) {
3629 quantity = ui_get_quantity(maxq);
3635 /* prompt for location */
3636 dir = ui_get_direction();
3637 if (dir == CANCEL) {
3640 x = actor->getX() + directionToDx(dir);
3641 y = actor->getY() + directionToDy(dir);
3643 /* put it on the map */
3644 obj = ie->type->createInstance();
3646 obj->setCount(quantity);
3647 if (place_get_movement_cost(actor->getPlace(), x, y,
3648 obj, 0) < PTABLE_NO_DROP)
3650 obj->relocate(actor->getPlace(), x, y,
3651 REL_NOSTEP, /* FIXME: really? */
3653 actor->takeOut(ie->type, quantity);
3654 actor->runHook(OBJ_HOOK_DROP_DONE, "pd", ie->type, quantity);
3656 else if (place_get_movement_cost(actor->getPlace(), actor->getX(), actor->getY(),
3657 obj, 0) < PTABLE_IMPASSABLE)
3659 obj->relocate(actor->getPlace(), actor->getX(), actor->getY(),
3660 REL_NOSTEP, /* FIXME: really? */
3662 actor->takeOut(ie->type, quantity);
3663 actor->runHook(OBJ_HOOK_DROP_DONE, "pd", ie->type, quantity);
3664 log_msg("%s¤Ï¹ç¤ï¤Ê¤¤¡ª", ie->type->getName());
3668 log_msg("%s¤òÃÖ¤±¤Ê¤¤¡ª", ie->type->getName());
3670 /* remove from party inventory */
3671 actor->decActionPoints(kern_intvar_get("AP_COST:drop_item"));
3674 mapUpdate(REPAINT_IF_DIRTY);
3680 static const void *cmd_select_generic()
3682 struct KeyHandler kh;
3683 struct ScrollerContext sc;
3685 foogodSetHintText(SCROLLER_HINT);
3686 foogodSetMode(FOOGOD_HINT);
3688 sc.selector = SelectSuperGeneric;
3689 sc.selection = NULL;
3693 eventPushKeyHandler(&kh);
3694 cmdwin_push("<ÁªÂò>");
3697 eventPopKeyHandler();
3699 foogodSetMode(FOOGOD_DEFAULT);
3700 return sc.selection;
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)
3708 cmdwin_spush(cmdstr);
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());
3718 pc = select_party_member();
3722 cmdwin_spush(pc->getName());
3732 log_msg("%s - %s¤Ï»à¤ó¤Ç¤¤¤ë¡ª", cmdstr, pc->getName());
3733 cmdwin_push("¤Ç¤¤Ê¤¤¡ª");
3737 /* sleeping actor? */
3738 if (pc->isAsleep()) {
3739 log_msg("%s - %s¤Ï¤Ò¤Ã¤¯¤êÊ֤äƤ¤¤Ó¤¤ò¤«¤¤¤Æ¤¤¤ë¡ª", cmdstr,
3741 cmdwin_push("¤Ç¤¤Ê¤¤¡ª");
3745 /* tell status who the actor is (sometimes it matters) */
3746 statusSelectCharacter(pc->getOrder());
3751 static void cmd_add_skill_set(struct node *head, class Character *pc,
3752 struct skill_set *skset)
3755 int pclvl = pc->getLevel();
3757 /* for each skill in the skill set */
3758 list_for_each(&skset->skills, elem) {
3760 struct skill_set_entry *ssent;
3762 ssent = list_entry(elem, struct skill_set_entry, list);
3764 /* is it a passive skill? */
3765 if (ssent->skill->passive) {
3769 /* is the character is of sufficient level? */
3770 if (pclvl < ssent->level) {
3774 /* add it to the list */
3775 node = node_new(ssent);
3776 node_add_tail(head, node);
3780 static void cmd_build_skill_list(struct node *head, class Character *pc)
3784 /* add species skills */
3786 && pc->species->skills) {
3787 cmd_add_skill_set(head, pc, pc->species->skills);
3790 /* add occupation skills */
3792 && pc->occ->skills) {
3793 cmd_add_skill_set(head, pc, pc->occ->skills);
3796 /* add bonus skills? */
3799 static int cmd_paint_skill(struct stat_super_generic_data *self,
3803 struct skill_set_entry *ssent = (struct skill_set_entry *)node->ptr;
3804 struct skill *skill = ssent->skill;
3805 const char *requires = "Requires:";
3811 /* remember original rect */
3815 if (rect->h < ASCII_H) {
3818 screenPrint(rect, 0, "^c+m%s^c-", skill->name);
3821 screenPrint(rect, SP_RIGHTJUSTIFIED,
3822 "^c+G¥ì¥Ù¥ë:^c+y%d^c- ËâÎÏ:^c+b%d^c- ¹ÔÆ°:^c+r%d^c-^c-",
3829 /* check for required items */
3830 if (! node_list_empty(&skill->tools)
3831 || ! list_empty(&skill->materials)) {
3833 if (rect->h < ASCII_H) {
3837 /* print "requires:" */
3838 screenPrint(rect, 0, " ^c+G%s^c-", requires);
3840 /* temporarily change x to print to right of "requires" */
3841 rect->x += (strlen(requires) + 1) * ASCII_W;
3844 node_for_each(&skill->tools, tnode) {
3846 if (rect->h < ASCII_H) {
3851 class ObjectType *tool = (class ObjectType*)tnode->ptr;
3852 struct inv_entry *ie=player_party->inventory->
3854 char tool_clr=(ie&&ie->count)?'g':'r';
3855 screenPrint(rect, 0, "^c+%c%s^c-", tool_clr,
3862 /* list materials */
3863 list_for_each(&skill->materials, elem) {
3865 if (rect->h < ASCII_H) {
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->
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-",
3889 /* restore rect x */
3894 /* figure out how much area we used */
3895 orect.h = rect->y - orect.y;
3897 /* if this is not the currently selected item then shade it */
3898 if (self->selected != node) {
3899 screenShade(&orect, 128);
3905 static void cmd_skill_list_unref(struct stat_super_generic_data *self)
3909 /* Decrement the refcount. */
3910 assert(self->refcount > 0);
3912 if (self->refcount > 0) {
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);
3925 static struct skill_set_entry *cmd_select_skill(class Character *pc)
3927 struct skill_set_entry *ssent;
3928 struct node *selected;
3929 struct stat_super_generic_data data;
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;
3938 /* put the status browser in selection mode */
3939 statusSetSuperGenericData(&data);
3940 statusPushMode(SuperGeneric);
3942 /* wait for user selection */
3943 selected = (struct node*)cmd_select_generic();
3945 /* extract result */
3947 ssent = (struct skill_set_entry *)selected->ptr;
3948 cmdwin_push(ssent->skill->name);
3951 cmdwin_push("²¿¤â¤·¤Ê¤¤");
3954 /* restore browser status mode */
3957 assert(! data.refcount);
3962 void cmdYuse(class Character *actor)
3964 struct skill_set_entry *ssent;
3965 struct skill *skill;
3966 int cant = 0, result = 0, yused = 0;
3968 /* select/verify the actor */
3969 if (!(actor = cmd_front_end(actor, "ǽÎÏ"))) {
3973 /* select the skill to yuse */
3974 if (!(ssent = cmd_select_skill(actor))) {
3977 skill = ssent->skill;
3978 log_begin("%s: %s - ", actor->getName(), skill->name);
3980 /* check wilderness */
3981 if (! skill->wilderness_ok
3982 && place_is_wilderness(actor->getPlace())) {
3984 log_msg("¹ÓÌî¤Ç¤Ï»È¤¨¤Ê¤¤¡ª");
3988 if (actor->getLevel() < ssent->level) {
3990 log_msg("¥ì¥Ù¥ë%d°Ê¾åɬÍפÀ¡ª", ssent->level);
3994 if (actor->getMana() < skill->mp) {
3996 log_msg("ËâÎϤ¬Â¤ê¤Ê¤¤¡ª");
4000 if (!node_list_empty(&skill->tools)) {
4002 node_for_each(&skill->tools, tnode) {
4003 class ObjectType *tool = (class ObjectType*)tnode->ptr;
4004 struct inv_entry *ie=player_party->inventory->
4006 if (!ie || !ie->count) {
4007 log_msg("%s¤¬É¬ÍפÀ¡ª", tool->getName());
4014 /* check material */
4015 if (! list_empty(&skill->materials)) {
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) {
4026 log_msg("%d¤Ä¤Î%s¤¬É¬ÍפÀ¡ª", mat->quantity,
4027 objtype->getName());
4034 && ! closure_exec(skill->can_yuse, "p", actor)) {
4040 cmdwin_push("¼ºÇÔ¡ª");
4041 log_end("^c+r¼ºÇÔ¡ª^c-");
4045 /* yuse the skill */
4046 result = closure_exec(skill->yuse, "p", actor);
4047 yused = cmd_eval_and_log_result(result);
4049 /* change ap/mp/xp and consume materials */
4051 actor->runHook(OBJ_HOOK_YUSE_DONE, 0);
4052 actor->addMana(0 - skill->mp);
4053 actor->decActionPoints(skill->ap);
4054 actor->addExperience(ssent->level);
4056 if (! list_empty(&skill->materials)) {
4058 struct skill_material *mat;
4059 list_for_each(&skill->materials, elem) {
4060 mat = list_entry(elem, struct skill_material,
4062 player_party->takeOut((class ObjectType*)
4071 #endif /* USE_SKILLS */
4073 bool cmdSetSoloMode(int party_member_index)
4075 class Character *solo_member = player_party->getMemberAtIndex(party_member_index);
4077 && ! solo_member->isIncapacitated()
4078 && solo_member->isOnMap()
4079 && solo_member->isPlayerControlled()
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())) {
4089 player_party->enableSoloMode(solo_member);
4095 bool cmdToggleFollowMode(void)
4098 if (player_party->getPartyControlMode() == PARTY_CONTROL_FOLLOW) {
4099 log_end("¤·¤Ê¤¤¡£");
4100 player_party->enableRoundRobinMode();
4104 player_party->enableFollowMode();