OSDN Git Service

Merge remote-tracking branch 'remotes/origin/feature/Fix-saved-floor-exceed' into...
[hengband/hengband.git] / src / birth / auto-roller.c
1 #include "birth/auto-roller.h"
2 #include "birth/birth-stat.h"
3 #include "birth/birth-util.h"
4 #include "cmd-io/cmd-gameoption.h"
5 #include "io/input-key-acceptor.h"
6 #include "main/sound-of-music.h"
7 #include "player/player-class.h"
8 #include "player/player-personality.h"
9 #include "player/player-race.h"
10 #include "player/player-status-table.h"
11 #include "system/game-option-types.h"
12 #include "term/screen-processor.h"
13 #include "term/term-color-types.h"
14 #include "util/int-char-converter.h"
15
16 /*! オートローラの能力値的要求水準 / Autoroll limit */
17 s16b stat_limit[6];
18
19 /*! オートローラの試行回数 / Autoroll round */
20 s32b auto_round;
21 s32b auto_upper_round;
22
23 /*! オートローラの要求値実現確率 */
24 s32b autoroll_chance;
25
26 /*!
27  * @breif オートローラーで指定した能力値以上が出る確率を計算する。
28  * @return 確率 / 100
29  */
30 static s32b get_autoroller_prob(int *minval)
31 {
32     /* 1 percent of the valid random space (60^6 && 72<sum<87) */
33     s32b tot_rand_1p = 320669745;
34     int i, j, tmp;
35     int ii[6];
36     int tval[6];
37     int tot = 0;
38
39     /* success count */
40     s32b succ = 0;
41
42     /* random combinations out of 60 (1d3+1d4+1d5) patterns */
43     int pp[18] = {
44         0, 0, 0, 0, 0, 0, 0, 0, /* 0-7 */
45         1, 3, 6, 9, 11, 11, 9, 6, 3, 1 /* 8-17 */
46     };
47
48     /* Copy */
49     for (i = 0; i < 6; i++) {
50         tval[i] = MAX(8, minval[i]);
51         tot += tval[i];
52     }
53
54     /* No Chance */
55     if (tot > 86)
56         return -999;
57
58     /* bubble sort for speed-up */
59     for (i = 0; i < 5; i++) {
60         for (j = 5; j > i; j--) {
61             if (tval[j - 1] < tval[j]) {
62                 tmp = tval[j - 1];
63                 tval[j - 1] = tval[j];
64                 tval[j] = tmp;
65             }
66         }
67     }
68
69     tot = 0;
70
71     /* calc. prob. */
72     for (ii[0] = tval[0]; ii[0] < 18; ii[0]++) {
73         for (ii[1] = tval[1]; ii[1] < 18; ii[1]++) {
74             for (ii[2] = tval[2]; ii[2] < 18; ii[2]++) {
75                 for (ii[3] = tval[3]; ii[3] < 18; ii[3]++) {
76                     for (ii[4] = tval[4]; ii[4] < 18; ii[4]++) {
77                         for (ii[5] = tval[5]; ii[5] < 18; ii[5]++) {
78                             tot = ii[0] + ii[1] + ii[2] + ii[3] + ii[4] + ii[5];
79
80                             if (tot > 86)
81                                 break;
82                             if (tot <= 72)
83                                 continue;
84
85                             succ += (pp[ii[0]] * pp[ii[1]] * pp[ii[2]] * pp[ii[3]] * pp[ii[4]] * pp[ii[5]]);
86
87                             /* If given condition is easy enough, quit calc. to save CPU. */
88                             if (succ > 320670)
89                                 return -1;
90                         }
91                     }
92                 }
93             }
94         }
95     }
96
97     return tot_rand_1p / succ;
98 }
99
100 /*!
101  * @brief オートローラで得たい能力値の基準を決める。
102  * @param creature_ptr プレーヤーへの参照ポインタ
103  * @return なし
104  */
105 bool get_stat_limits(player_type *creature_ptr)
106 {
107     int col_stat = 25;
108
109     clear_from(10);
110     put_str(_("最低限得たい能力値を設定して下さい。", "Set minimum stats."), 10, 10);
111     put_str(_("2/8で項目選択、4/6で値の増減、Enterで次へ", "2/8 for Select, 4/6 for Change value, Enter for Goto next"), 11, 10);
112     put_str(_("         基本値  種族 職業 性格     合計値  最大値", "           Base   Rac  Cla  Per      Total  Maximum"), 13, 10);
113
114     put_str(_("確率: 非常に容易(1/10000以上)", "Prob: Quite Easy(>1/10000)"), 23, col_stat);
115
116     int cval[6];
117     char buf[80];
118     char cur[80];
119     char inp[80];
120     for (int i = 0; i < A_MAX; i++) {
121         cval[i] = 3;
122         int j = rp_ptr->r_adj[i] + cp_ptr->c_adj[i] + ap_ptr->a_adj[i];
123         int m = adjust_stat(17, j);
124         if (m > 18)
125             sprintf(cur, "18/%02d", (m - 18));
126         else
127             sprintf(cur, "%2d", m);
128
129         m = adjust_stat(cval[i], j);
130         if (m > 18)
131             sprintf(inp, "18/%02d", (m - 18));
132         else
133             sprintf(inp, "%2d", m);
134
135         sprintf(buf, "%6s       %2d   %+3d  %+3d  %+3d  =  %6s  %6s", stat_names[i], cval[i], rp_ptr->r_adj[i], cp_ptr->c_adj[i], ap_ptr->a_adj[i], inp, cur);
136         put_str(buf, 14 + i, 10);
137     }
138
139     int cs = 0;
140     int os = 6;
141     while (TRUE) {
142         if (cs != os) {
143             if (os == 7) {
144                 autoroll_chance = get_autoroller_prob(cval);
145                 if (autoroll_chance == -999)
146                     sprintf(buf, _("確率: 不可能(合計86超)       ", "Prob: Impossible(>86 tot stats)"));
147                 else if (autoroll_chance < 1)
148                     sprintf(buf, _("確率: 非常に容易(1/10000以上)", "Prob: Quite Easy(>1/10000)     "));
149                 else
150                     sprintf(buf, _("確率: 約 1/%8d00          ", "Prob: ~ 1/%8d00            "), autoroll_chance);
151                 put_str(buf, 23, col_stat);
152             }
153             else if (os == 6) {
154                 c_put_str(TERM_WHITE, _("決定する", "Accept"), 21, 35);
155             } else if (os < A_MAX) {
156                 c_put_str(TERM_WHITE, cur, 14 + os, 10);
157             }
158             if (cs == 6) {
159                 c_put_str(TERM_YELLOW, _("決定する", "Accept"), 21, 35);
160             } else {
161                 int j = rp_ptr->r_adj[cs] + cp_ptr->c_adj[cs] + ap_ptr->a_adj[cs];
162                 int m = adjust_stat(cval[cs], j);
163                 if (m > 18)
164                     sprintf(inp, "18/%02d", (m - 18));
165                 else
166                     sprintf(inp, "%2d", m);
167
168                 sprintf(
169                     cur, "%6s       %2d   %+3d  %+3d  %+3d  =  %6s", stat_names[cs], cval[cs], rp_ptr->r_adj[cs], cp_ptr->c_adj[cs], ap_ptr->a_adj[cs], inp);
170                 c_put_str(TERM_YELLOW, cur, 14 + cs, 10);
171             }
172
173             os = cs;
174         }
175
176         char c = inkey();
177         switch (c) {
178         case 'Q':
179             birth_quit();
180             break;
181         case 'S':
182             return FALSE;
183         case ESCAPE:
184             break;
185         case ' ':
186         case '\r':
187         case '\n':
188             if (cs == 6)
189                 break;
190             cs++;
191             c = '2';
192             break;
193         case '8':
194         case 'k':
195             if (cs > 0)
196                 cs--;
197             break;
198         case '2':
199         case 'j':
200             if (cs < A_MAX)
201                 cs++;
202             break;
203         case '4':
204         case 'h':
205             if (cs != 6) {
206                 if (cval[cs] == 3) {
207                     cval[cs] = 17;
208                     os = 7;
209                 } else if (cval[cs] > 3) {
210                     cval[cs]--;
211                     os = 7;
212                 } else
213                     return FALSE;
214             }
215
216             break;
217         case '6':
218         case 'l':
219             if (cs != 6) {
220                 if (cval[cs] == 17) {
221                     cval[cs] = 3;
222                     os = 7;
223                 } else if (cval[cs] < 17) {
224                     cval[cs]++;
225                     os = 7;
226                 } else
227                     return FALSE;
228             }
229
230             break;
231         case 'm':
232             if (cs != 6) {
233                 cval[cs] = 17;
234                 os = 7;
235             }
236
237             break;
238         case 'n':
239             if (cs != 6) {
240                 cval[cs] = 3;
241                 os = 7;
242             }
243
244             break;
245         case '?':
246 #ifdef JP
247             show_help(creature_ptr, "jbirth.txt#AutoRoller");
248 #else
249             show_help(creature_ptr, "birth.txt#AutoRoller");
250 #endif
251             break;
252         case '=':
253             screen_save();
254 #ifdef JP
255             do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, "初期オプション((*)はスコアに影響)");
256 #else
257             do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, "Birth Options ((*)) affect score");
258 #endif
259
260             screen_load();
261             break;
262         default:
263             bell();
264             break;
265         }
266
267         if (c == ESCAPE || ((c == ' ' || c == '\r' || c == '\n') && cs == 6 && autoroll_chance != -999))
268             break;
269     }
270
271     for (int i = 0; i < A_MAX; i++)
272         stat_limit[i] = (s16b)cval[i];
273
274     return TRUE;
275 }
276
277 void initialize_chara_limit(chara_limit_type *chara_limit_ptr)
278 {
279     chara_limit_ptr->agemin = 0;
280     chara_limit_ptr->agemax = 0;
281     chara_limit_ptr->htmin = 0;
282     chara_limit_ptr->htmax = 0;
283     chara_limit_ptr->wtmin = 0;
284     chara_limit_ptr->wtmax = 0;
285     chara_limit_ptr->scmin = 0;
286     chara_limit_ptr->scmax = 0;
287 }
288
289 /*!
290  * @brief オートローラで得たい年齢、身長、体重、社会的地位の基準を決める。
291  * @return なし
292  */
293 bool get_chara_limits(player_type *creature_ptr, chara_limit_type *chara_limit_ptr)
294 {
295 #define MAXITEMS 8
296
297     char buf[80], cur[80];
298     concptr itemname[] = { _("年齢", "age"), _("身長(インチ)", "height"), _("体重(ポンド)", "weight"), _("社会的地位", "social class") };
299
300     clear_from(10);
301     put_str(_("2/4/6/8で項目選択、+/-で値の増減、Enterで次へ", "2/4/6/8 for Select, +/- for Change value, Enter for Goto next"), 11, 10);
302     put_str(
303         _("注意:身長と体重の最大値/最小値ぎりぎりの値は非常に出現確率が低くなります。", "Caution: Values near minimum or maximum are extremely rare."), 23, 2);
304
305     int max_percent, min_percent;
306     if (creature_ptr->psex == SEX_MALE) {
307         max_percent = (int)(rp_ptr->m_b_ht + rp_ptr->m_m_ht * 4 - 1) * 100 / (int)(rp_ptr->m_b_ht);
308         min_percent = (int)(rp_ptr->m_b_ht - rp_ptr->m_m_ht * 4 + 1) * 100 / (int)(rp_ptr->m_b_ht);
309     } else {
310         max_percent = (int)(rp_ptr->f_b_ht + rp_ptr->f_m_ht * 4 - 1) * 100 / (int)(rp_ptr->f_b_ht);
311         min_percent = (int)(rp_ptr->f_b_ht - rp_ptr->f_m_ht * 4 + 1) * 100 / (int)(rp_ptr->f_b_ht);
312     }
313
314     put_str(_("体格/地位の最小値/最大値を設定して下さい。", "Set minimum/maximum attribute."), 10, 10);
315     put_str(_("  項    目                 最小値  最大値", " Parameter                    Min     Max"), 13, 20);
316     int mval[MAXITEMS];
317     int cval[MAXITEMS];
318     for (int i = 0; i < MAXITEMS; i++) {
319         int m;
320         switch (i) {
321         case 0: /* Minimum age */
322             m = rp_ptr->b_age + 1;
323             break;
324         case 1: /* Maximum age */
325             m = rp_ptr->b_age + rp_ptr->m_age;
326             break;
327
328         case 2: /* Minimum height */
329             if (creature_ptr->psex == SEX_MALE)
330                 m = rp_ptr->m_b_ht - rp_ptr->m_m_ht * 4 + 1;
331             else
332                 m = rp_ptr->f_b_ht - rp_ptr->f_m_ht * 4 + 1;
333             break;
334         case 3: /* Maximum height */
335             if (creature_ptr->psex == SEX_MALE)
336                 m = rp_ptr->m_b_ht + rp_ptr->m_m_ht * 4 - 1;
337             else
338                 m = rp_ptr->f_b_ht + rp_ptr->f_m_ht * 4 - 1;
339             break;
340         case 4: /* Minimum weight */
341             if (creature_ptr->psex == SEX_MALE)
342                 m = (rp_ptr->m_b_wt * min_percent / 100) - (rp_ptr->m_m_wt * min_percent / 75) + 1;
343             else
344                 m = (rp_ptr->f_b_wt * min_percent / 100) - (rp_ptr->f_m_wt * min_percent / 75) + 1;
345             break;
346         case 5: /* Maximum weight */
347             if (creature_ptr->psex == SEX_MALE)
348                 m = (rp_ptr->m_b_wt * max_percent / 100) + (rp_ptr->m_m_wt * max_percent / 75) - 1;
349             else
350                 m = (rp_ptr->f_b_wt * max_percent / 100) + (rp_ptr->f_m_wt * max_percent / 75) - 1;
351             break;
352         case 6: /* Minimum social class */
353             m = 1;
354             break;
355         case 7: /* Maximum social class */
356             m = 100;
357             break;
358         default:
359             m = 1;
360             break;
361         }
362
363         mval[i] = m;
364         cval[i] = m;
365     }
366
367     for (int i = 0; i < 4; i++) {
368         sprintf(buf, "%-12s (%3d - %3d)", itemname[i], mval[i * 2], mval[i * 2 + 1]);
369         put_str(buf, 14 + i, 20);
370         for (int j = 0; j < 2; j++) {
371             sprintf(buf, "     %3d", cval[i * 2 + j]);
372             put_str(buf, 14 + i, 45 + 8 * j);
373         }
374     }
375
376     int cs = 0;
377     int os = MAXITEMS;
378     while (TRUE) {
379         if (cs != os) {
380             const char accept[] = _("決定する", "Accept");
381             if (os == MAXITEMS)
382                 c_put_str(TERM_WHITE, accept, 19, 35);
383             else
384                 c_put_str(TERM_WHITE, cur, 14 + os / 2, 45 + 8 * (os % 2));
385
386             if (cs == MAXITEMS) {
387                 c_put_str(TERM_YELLOW, accept, 19, 35);
388             } else {
389                 sprintf(cur, "     %3d", cval[cs]);
390                 c_put_str(TERM_YELLOW, cur, 14 + cs / 2, 45 + 8 * (cs % 2));
391             }
392
393             os = cs;
394         }
395
396         char c = inkey();
397         switch (c) {
398         case 'Q':
399             birth_quit();
400             break;
401         case 'S':
402             return FALSE;
403         case ESCAPE:
404             break; /*後でもう一回breakせんと*/
405         case ' ':
406         case '\r':
407         case '\n':
408             if (cs == MAXITEMS)
409                 break;
410             cs++;
411             c = '6';
412             break;
413         case '8':
414         case 'k':
415             if (cs - 2 >= 0)
416                 cs -= 2;
417             break;
418         case '2':
419         case 'j':
420             if (cs < MAXITEMS)
421                 cs += 2;
422             if (cs > MAXITEMS)
423                 cs = MAXITEMS;
424             break;
425         case '4':
426         case 'h':
427             if (cs > 0)
428                 cs--;
429             break;
430         case '6':
431         case 'l':
432             if (cs < MAXITEMS)
433                 cs++;
434             break;
435         case '-':
436         case '<':
437             if (cs != MAXITEMS) {
438                 if (cs % 2) {
439                     if (cval[cs] > cval[cs - 1]) {
440                         cval[cs]--;
441                         os = 127;
442                     }
443                 } else {
444                     if (cval[cs] > mval[cs]) {
445                         cval[cs]--;
446                         os = 127;
447                     }
448                 }
449             }
450
451             break;
452         case '+':
453         case '>':
454             if (cs != MAXITEMS) {
455                 if (cs % 2) {
456                     if (cval[cs] < mval[cs]) {
457                         cval[cs]++;
458                         os = 127;
459                     }
460                 } else {
461                     if (cval[cs] < cval[cs + 1]) {
462                         cval[cs]++;
463                         os = 127;
464                     }
465                 }
466             }
467
468             break;
469         case 'm':
470             if (cs != MAXITEMS) {
471                 if (cs % 2) {
472                     if (cval[cs] < mval[cs]) {
473                         cval[cs] = mval[cs];
474                         os = 127;
475                     }
476                 } else {
477                     if (cval[cs] < cval[cs + 1]) {
478                         cval[cs] = cval[cs + 1];
479                         os = 127;
480                     }
481                 }
482             }
483
484             break;
485         case 'n':
486             if (cs != MAXITEMS) {
487                 if (cs % 2) {
488                     if (cval[cs] > cval[cs - 1]) {
489                         cval[cs] = cval[cs - 1];
490                         os = 255;
491                     }
492                 } else {
493                     if (cval[cs] > mval[cs]) {
494                         cval[cs] = mval[cs];
495                         os = 255;
496                     }
497                 }
498             }
499
500             break;
501         case '?':
502 #ifdef JP
503             show_help(creature_ptr, "jbirth.txt#AutoRoller");
504 #else
505             show_help(creature_ptr, "birth.txt#AutoRoller");
506 #endif
507             break;
508         case '=':
509             screen_save();
510             do_cmd_options_aux(creature_ptr, OPT_PAGE_BIRTH, _("初期オプション((*)はスコアに影響)", "Birth Options ((*)) affect score"));
511             screen_load();
512             break;
513         default:
514             bell();
515             break;
516         }
517
518         if (c == ESCAPE || ((c == ' ' || c == '\r' || c == '\n') && cs == MAXITEMS))
519             break;
520     }
521
522     chara_limit_ptr->agemin = (s16b)cval[0];
523     chara_limit_ptr->agemax = (s16b)cval[1];
524     chara_limit_ptr->htmin = (s16b)cval[2];
525     chara_limit_ptr->htmax = (s16b)cval[3];
526     chara_limit_ptr->wtmin = (s16b)cval[4];
527     chara_limit_ptr->wtmax = (s16b)cval[5];
528     chara_limit_ptr->scmin = (s16b)cval[6];
529     chara_limit_ptr->scmax = (s16b)cval[7];
530     return TRUE;
531 }