2 * @brief ウルティマ4を参考にした徳のシステムの実装 / Enable an Ultima IV style "avatar" game where you try to achieve perfection in various virtues.
9 * Copyright (c) 1989 James E. Wilson, Christopher J. Stuart
10 * This software may be copied and distributed for educational, research, and
11 * not for profit purposes provided that this copyright and statement are
12 * included in all such copies.
15 #include "avatar/avatar.h"
16 #include "core/player-update-types.h"
17 #include "game-option/text-display-options.h"
18 #include "player-info/class-info.h"
19 #include "player-info/race-types.h"
20 #include "realm/realm-names-table.h"
21 #include "system/player-type-definition.h"
24 * 徳の名称 / The names of the virtues
26 concptr virtue[MAX_VIRTUE] = {
33 _("啓", "Enlightenment"),
44 _("個", "Individualism"),
48 * @brief 該当の徳がプレイヤーに指定されているか否かに応じつつ、大小を比較する。
49 * @details 徳がない場合は値0として比較する。
50 * @param type 比較したい徳のID
52 * @param tekitou VIRTUE_LARGE = 基準値より大きいか / VIRTUE_SMALL = 基準値より小さいか
56 bool compare_virtue(player_type *player_ptr, int type, int num, int tekitou)
58 int vir = virtue_number(player_ptr, type) ? player_ptr->virtues[virtue_number(player_ptr, type) - 1] : 0;
76 * @brief プレイヤーの指定の徳が何番目のスロットに登録されているかを返す。 / Aux function
77 * @param type 確認したい徳のID
78 * @return スロットがあるならばスロットのID(0~7)+1、ない場合は0を返す。
80 int virtue_number(player_type *player_ptr, int type)
82 for (int i = 0; i < 8; i++)
83 if (player_ptr->vir_types[i] == type)
90 * @brief プレイヤーの職業や種族に依存しないランダムな徳を取得する / Aux function
91 * @param which 確認したい徳のID
93 static void get_random_virtue(player_type *player_ptr, int which)
96 while (!(type) || virtue_number(player_ptr, type)) {
97 switch (randint1(29)) {
148 player_ptr->vir_types[which] = (int16_t)type;
152 * @brief プレイヤーの選んだ魔法領域に応じて対応する徳を返す。
153 * @param realm 魔法領域のID
156 static enum virtue_idx get_realm_virtues(player_type *player_ptr, int16_t realm)
160 if (virtue_number(player_ptr, V_VITALITY))
165 if (virtue_number(player_ptr, V_KNOWLEDGE))
170 if (virtue_number(player_ptr, V_NATURE))
175 if (virtue_number(player_ptr, V_CHANCE))
176 return V_INDIVIDUALISM;
186 if (virtue_number(player_ptr, V_ENCHANT))
187 return V_INDIVIDUALISM;
191 if (virtue_number(player_ptr, V_JUSTICE))
196 if (virtue_number(player_ptr, V_JUSTICE))
201 if (virtue_number(player_ptr, V_COMPASSION))
211 * @brief 作成中のプレイヤーキャラクターに徳8種類を与える。 / Select virtues & reset values for a new character
212 * @details 職業に応じて1~4種が固定、種族に応じて1種類が与えられ、後は重複なくランダムに選択される。
214 void initialize_virtues(player_type *player_ptr)
220 for (i = 0; i < 8; i++) {
221 player_ptr->virtues[i] = 0;
222 player_ptr->vir_types[i] = 0;
227 /* Get pre-defined types */
228 /* 1 or more virtues based on class */
229 switch (player_ptr->pclass) {
230 case PlayerClassType::WARRIOR:
231 case PlayerClassType::SAMURAI:
232 player_ptr->vir_types[i++] = V_VALOUR;
233 player_ptr->vir_types[i++] = V_HONOUR;
235 case PlayerClassType::MAGE:
236 player_ptr->vir_types[i++] = V_KNOWLEDGE;
237 player_ptr->vir_types[i++] = V_ENCHANT;
239 case PlayerClassType::PRIEST:
240 player_ptr->vir_types[i++] = V_FAITH;
241 player_ptr->vir_types[i++] = V_TEMPERANCE;
243 case PlayerClassType::ROGUE:
244 case PlayerClassType::SNIPER:
245 player_ptr->vir_types[i++] = V_HONOUR;
247 case PlayerClassType::RANGER:
248 case PlayerClassType::ARCHER:
249 player_ptr->vir_types[i++] = V_NATURE;
250 player_ptr->vir_types[i++] = V_TEMPERANCE;
252 case PlayerClassType::PALADIN:
253 player_ptr->vir_types[i++] = V_JUSTICE;
254 player_ptr->vir_types[i++] = V_VALOUR;
255 player_ptr->vir_types[i++] = V_HONOUR;
256 player_ptr->vir_types[i++] = V_FAITH;
258 case PlayerClassType::WARRIOR_MAGE:
259 case PlayerClassType::RED_MAGE:
260 player_ptr->vir_types[i++] = V_ENCHANT;
261 player_ptr->vir_types[i++] = V_VALOUR;
263 case PlayerClassType::CHAOS_WARRIOR:
264 player_ptr->vir_types[i++] = V_CHANCE;
265 player_ptr->vir_types[i++] = V_INDIVIDUALISM;
267 case PlayerClassType::MONK:
268 case PlayerClassType::FORCETRAINER:
269 player_ptr->vir_types[i++] = V_FAITH;
270 player_ptr->vir_types[i++] = V_HARMONY;
271 player_ptr->vir_types[i++] = V_TEMPERANCE;
272 player_ptr->vir_types[i++] = V_PATIENCE;
274 case PlayerClassType::MINDCRAFTER:
275 case PlayerClassType::MIRROR_MASTER:
276 player_ptr->vir_types[i++] = V_HARMONY;
277 player_ptr->vir_types[i++] = V_ENLIGHTEN;
278 player_ptr->vir_types[i++] = V_PATIENCE;
280 case PlayerClassType::HIGH_MAGE:
281 case PlayerClassType::SORCERER:
282 player_ptr->vir_types[i++] = V_ENLIGHTEN;
283 player_ptr->vir_types[i++] = V_ENCHANT;
284 player_ptr->vir_types[i++] = V_KNOWLEDGE;
286 case PlayerClassType::TOURIST:
287 player_ptr->vir_types[i++] = V_ENLIGHTEN;
288 player_ptr->vir_types[i++] = V_CHANCE;
290 case PlayerClassType::IMITATOR:
291 player_ptr->vir_types[i++] = V_CHANCE;
293 case PlayerClassType::BLUE_MAGE:
294 player_ptr->vir_types[i++] = V_CHANCE;
295 player_ptr->vir_types[i++] = V_KNOWLEDGE;
297 case PlayerClassType::BEASTMASTER:
298 player_ptr->vir_types[i++] = V_NATURE;
299 player_ptr->vir_types[i++] = V_CHANCE;
300 player_ptr->vir_types[i++] = V_VITALITY;
302 case PlayerClassType::MAGIC_EATER:
303 player_ptr->vir_types[i++] = V_ENCHANT;
304 player_ptr->vir_types[i++] = V_KNOWLEDGE;
306 case PlayerClassType::BARD:
307 player_ptr->vir_types[i++] = V_HARMONY;
308 player_ptr->vir_types[i++] = V_COMPASSION;
310 case PlayerClassType::CAVALRY:
311 player_ptr->vir_types[i++] = V_VALOUR;
312 player_ptr->vir_types[i++] = V_HARMONY;
314 case PlayerClassType::BERSERKER:
315 player_ptr->vir_types[i++] = V_VALOUR;
316 player_ptr->vir_types[i++] = V_INDIVIDUALISM;
318 case PlayerClassType::SMITH:
319 player_ptr->vir_types[i++] = V_HONOUR;
320 player_ptr->vir_types[i++] = V_KNOWLEDGE;
322 case PlayerClassType::NINJA:
323 player_ptr->vir_types[i++] = V_PATIENCE;
324 player_ptr->vir_types[i++] = V_KNOWLEDGE;
325 player_ptr->vir_types[i++] = V_FAITH;
326 player_ptr->vir_types[i++] = V_UNLIFE;
328 case PlayerClassType::ELEMENTALIST:
329 player_ptr->vir_types[i++] = V_NATURE;
331 case PlayerClassType::MAX:
335 /* Get one virtue based on race */
336 switch (player_ptr->prace) {
337 case PlayerRaceType::HUMAN:
338 case PlayerRaceType::HALF_ELF:
339 case PlayerRaceType::DUNADAN:
340 player_ptr->vir_types[i++] = V_INDIVIDUALISM;
342 case PlayerRaceType::ELF:
343 case PlayerRaceType::SPRITE:
344 case PlayerRaceType::ENT:
345 case PlayerRaceType::MERFOLK:
346 player_ptr->vir_types[i++] = V_NATURE;
348 case PlayerRaceType::HOBBIT:
349 case PlayerRaceType::HALF_OGRE:
350 player_ptr->vir_types[i++] = V_TEMPERANCE;
352 case PlayerRaceType::DWARF:
353 case PlayerRaceType::KLACKON:
354 case PlayerRaceType::ANDROID:
355 player_ptr->vir_types[i++] = V_DILIGENCE;
357 case PlayerRaceType::GNOME:
358 case PlayerRaceType::CYCLOPS:
359 player_ptr->vir_types[i++] = V_KNOWLEDGE;
361 case PlayerRaceType::HALF_ORC:
362 case PlayerRaceType::AMBERITE:
363 case PlayerRaceType::KOBOLD:
364 player_ptr->vir_types[i++] = V_HONOUR;
366 case PlayerRaceType::HALF_TROLL:
367 case PlayerRaceType::BARBARIAN:
368 player_ptr->vir_types[i++] = V_VALOUR;
370 case PlayerRaceType::HIGH_ELF:
371 case PlayerRaceType::KUTAR:
372 player_ptr->vir_types[i++] = V_VITALITY;
374 case PlayerRaceType::HALF_GIANT:
375 case PlayerRaceType::GOLEM:
376 case PlayerRaceType::ARCHON:
377 case PlayerRaceType::BALROG:
378 player_ptr->vir_types[i++] = V_JUSTICE;
380 case PlayerRaceType::HALF_TITAN:
381 player_ptr->vir_types[i++] = V_HARMONY;
383 case PlayerRaceType::YEEK:
384 player_ptr->vir_types[i++] = V_SACRIFICE;
386 case PlayerRaceType::MIND_FLAYER:
387 player_ptr->vir_types[i++] = V_ENLIGHTEN;
389 case PlayerRaceType::DARK_ELF:
390 case PlayerRaceType::DRACONIAN:
391 case PlayerRaceType::S_FAIRY:
392 player_ptr->vir_types[i++] = V_ENCHANT;
394 case PlayerRaceType::NIBELUNG:
395 player_ptr->vir_types[i++] = V_PATIENCE;
397 case PlayerRaceType::IMP:
398 player_ptr->vir_types[i++] = V_FAITH;
400 case PlayerRaceType::ZOMBIE:
401 case PlayerRaceType::SKELETON:
402 case PlayerRaceType::VAMPIRE:
403 case PlayerRaceType::SPECTRE:
404 player_ptr->vir_types[i++] = V_UNLIFE;
406 case PlayerRaceType::BEASTMAN:
407 player_ptr->vir_types[i++] = V_CHANCE;
409 case PlayerRaceType::MAX:
413 /* Get a virtue for realms */
414 if (player_ptr->realm1) {
415 tmp_vir = get_realm_virtues(player_ptr, player_ptr->realm1);
417 player_ptr->vir_types[i++] = tmp_vir;
420 if (player_ptr->realm2) {
421 tmp_vir = get_realm_virtues(player_ptr, player_ptr->realm2);
423 player_ptr->vir_types[i++] = tmp_vir;
426 /* Eliminate doubles */
427 for (i = 0; i < 8; i++)
428 for (j = i + 1; j < 8; j++)
429 if ((player_ptr->vir_types[j] != 0) && (player_ptr->vir_types[j] == player_ptr->vir_types[i]))
430 player_ptr->vir_types[j] = 0;
432 /* Fill in the blanks */
433 for (i = 0; i < 8; i++)
434 if (player_ptr->vir_types[i] == 0)
435 get_random_virtue(player_ptr, i);
439 * @brief 対応する徳をプレイヤーがスロットに登録している場合に加減を行う。
440 * @details 範囲は-125~125、基本的に絶対値が大きいほど絶対値が上がり辛くなる。
444 void chg_virtue(player_type *player_ptr, int virtue_id, int amount)
446 for (int i = 0; i < 8; i++) {
447 if (player_ptr->vir_types[i] != virtue_id)
451 if ((amount + player_ptr->virtues[i] > 50) && one_in_(2)) {
452 player_ptr->virtues[i] = MAX(player_ptr->virtues[i], 50);
456 if ((amount + player_ptr->virtues[i] > 80) && one_in_(2)) {
457 player_ptr->virtues[i] = MAX(player_ptr->virtues[i], 80);
461 if ((amount + player_ptr->virtues[i] > 100) && one_in_(2)) {
462 player_ptr->virtues[i] = MAX(player_ptr->virtues[i], 100);
466 if (amount + player_ptr->virtues[i] > 125)
467 player_ptr->virtues[i] = 125;
469 player_ptr->virtues[i] = player_ptr->virtues[i] + amount;
471 if ((amount + player_ptr->virtues[i] < -50) && one_in_(2)) {
472 player_ptr->virtues[i] = MIN(player_ptr->virtues[i], -50);
476 if ((amount + player_ptr->virtues[i] < -80) && one_in_(2)) {
477 player_ptr->virtues[i] = MIN(player_ptr->virtues[i], -80);
481 if ((amount + player_ptr->virtues[i] < -100) && one_in_(2)) {
482 player_ptr->virtues[i] = MIN(player_ptr->virtues[i], -100);
486 if (amount + player_ptr->virtues[i] < -125)
487 player_ptr->virtues[i] = -125;
489 player_ptr->virtues[i] = player_ptr->virtues[i] + amount;
492 player_ptr->update |= PU_BONUS;
498 * @brief 対応する徳をプレイヤーがスロットに登録している場合に固定値をセットする
500 * @param amount セットしたい値
502 void set_virtue(player_type *player_ptr, int virtue_id, int amount)
504 for (int i = 0; i < 8; i++)
505 if (player_ptr->vir_types[i] == virtue_id) {
506 player_ptr->virtues[i] = (int16_t)amount;
513 * @param out_file ファイルポインタ
515 void dump_virtues(player_type *player_ptr, FILE *out_file)
520 for (int v_nr = 0; v_nr < 8; v_nr++) {
521 GAME_TEXT vir_name[20];
522 int tester = player_ptr->virtues[v_nr];
523 strcpy(vir_name, virtue[(player_ptr->vir_types[v_nr]) - 1]);
524 concptr vir_val = show_actual_value ? format(" (%d)", tester) : "";
525 if (player_ptr->vir_types[v_nr] == 0 || player_ptr->vir_types[v_nr] > MAX_VIRTUE)
526 fprintf(out_file, _("おっと。%sの情報なし。", "Oops. No info about %s."), vir_name);
528 else if (tester < -100)
529 fprintf(out_file, _("[%s]の対極%s", "You are the polar opposite of %s.%s"), vir_name, vir_val);
530 else if (tester < -80)
531 fprintf(out_file, _("[%s]の大敵%s", "You are an arch-enemy of %s.%s"), vir_name, vir_val);
532 else if (tester < -60)
533 fprintf(out_file, _("[%s]の強敵%s", "You are a bitter enemy of %s.%s"), vir_name, vir_val);
534 else if (tester < -40)
535 fprintf(out_file, _("[%s]の敵%s", "You are an enemy of %s.%s"), vir_name, vir_val);
536 else if (tester < -20)
537 fprintf(out_file, _("[%s]の罪者%s", "You have sinned against %s.%s"), vir_name, vir_val);
539 fprintf(out_file, _("[%s]の迷道者%s", "You have strayed from the path of %s.%s"), vir_name, vir_val);
540 else if (tester == 0)
541 fprintf(out_file, _("[%s]の中立者%s", "You are neutral to %s.%s"), vir_name, vir_val);
542 else if (tester < 20)
543 fprintf(out_file, _("[%s]の小徳者%s", "You are somewhat virtuous in %s.%s"), vir_name, vir_val);
544 else if (tester < 40)
545 fprintf(out_file, _("[%s]の中徳者%s", "You are virtuous in %s.%s"), vir_name, vir_val);
546 else if (tester < 60)
547 fprintf(out_file, _("[%s]の高徳者%s", "You are very virtuous in %s.%s"), vir_name, vir_val);
548 else if (tester < 80)
549 fprintf(out_file, _("[%s]の覇者%s", "You are a champion of %s.%s"), vir_name, vir_val);
550 else if (tester < 100)
551 fprintf(out_file, _("[%s]の偉大な覇者%s", "You are a great champion of %s.%s"), vir_name, vir_val);
553 fprintf(out_file, _("[%s]の具現者%s", "You are the living embodiment of %s.%s"), vir_name, vir_val);
555 fprintf(out_file, "\n");