トップ 追記

SikabaneWorksが関係するコンテンツ(主に*band系ローグライク)の開発近況・補足から全く個人的な雑記まで。

[WEB:屍の見える丘公園]| [RSS]

Angband | Badiashimshe | C# | CRAUZEL | D'angband/小説草稿 | D'angband/開発 | DarkSouls | Demon'sSouls | DungeonCrawl | ElvenUteruses | Haskell | Hengband | J9シリーズ | LEGO | LineDrawing | MISC | MTG | Mac | Math | Moria | R-18 | Roguelike | Rough | RoughSketch | Ruby | SDL | UNIX | VMware | WarHammer | Zangband | アタシラヂョウヲウ | イラスト | ガジェット | ゲーム | ゲーム紹介 | ゲーム製作技術 | ゲーム論 | スケッチ | ツクール | テクノロジー | ニコニコ動画 | ファルコム | ファンタジー | マリオ | ヴィーヤウトゥムノ | 別記事追加予定 | 変愚蛮怒 | 変愚蛮怒/スポイラー | 変愚蛮怒/元ネタ探訪 | 変愚蛮怒/攻略 | 変愚蛮怒/開発 | 宗教 | 情報 | 政治 | 文字コード | 日ペ昔話 | 東方ワンドロ | 東方外法漢女 | 歴史 | 漫画製作 | 版権絵 | 画像処理 | 翻訳 | 自然言語 | 艦隊これくしょん | 落書き | 言語解析 | 読書 | 超人ロック | 追記予定 | 通信 | 阿片窟 | 馬鹿馬鹿蛮怒/開発 | 魔法少女まどか☆マギカ | 魚類版深夜の真剣お絵描き60分一本勝負


2018/12/10

[変愚蛮怒/開発]変愚蛮怒開発日誌part101…特別編「変愚蛮怒の種族実装例 ~MtGの主に青いヤクザ種族~(前編/遅刻した)」

はじめに

という訳でAdvent Calendar 10日目埋め、ついでに遅刻しました。ゆ る し て。

前回、新しい性格の実装(調整)をあっさり1日で済ませてしまいまして、そんじゃあ続けて次に簡単そうな種族でも行ってみようかという例を、前後編か前中後編くらいに分けてやっていこうと思います。

ファンタジーな種族が何だかんだ既にそろい踏みな中、足りない奴をD'ang旧ソースや、ニワカハマりしたMtGなどで探った結果、赤のゴブリン、緑のエルフに並ぶ、青の囲んで棒で叩くヤクザ種族、マーフォークで行ってみようと思います。

ちなみに私はレガシー2tで難題の予見者を出したり、現実を砕くもので暴力の限りを尽くしたり、終末を招くものでねっとりアド稼いだり、積み上げたマナ加速の果てにウラモグ兄貴を叩きつけると絶頂しそうになる変態糞エルドラージ使いなので、無色マナ塗れになりたい奴、至急メールくれや(自分語り)

性格より少々と面倒な種族実装

という訳で、まずさっさと性格の時同様、ハードコーディング上の基礎ステ設定から行ってみましょう。

まずdefines.hに新しくマーフォークのIDを定義し、種族最大数を増やします。

diff --git a/src/defines.h b/src/defines.h
index ec8e7db..b6457ab 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -774,11 +774,12 @@
 #define RACE_S_FAIRY            34
 #define RACE_KUTAR              35
 #define RACE_ANDROID            36
+#define RACE_MERFOLK            37

 /*
  * Maximum number of player "race" types (see "table.c", etc)
  */
-#define MAX_RACES               37
+#define MAX_RACES               38

続けてプレイヤー種族のステータステーブル player_race race_info[MAX_RACES] にマーフォークのステータスを書き込みましょう。

--- a/src/tables.c
+++ b/src/tables.c
@@ -2768,6 +2768,22 @@ const player_race race_info[MAX_RACES] =
 		0,
 		0x0800001,
 	},
+	{
+#ifdef JP
+		"マーフォーク",
+#endif
+		"Merfolk",
+
+		{ -1,  0,  2,  1,  -1,  1},
+			2,  3,  2,  1, 6,  11, -1,  5,
+			10,  130,
+			24, 16,
+			66,  6, 130, 15,
+			62,  6, 100, 10,
+			2,
+			0xE77E7FF,
+	},
+
 };

現状基本的ステータス以外はハーフエルフからのコピーです。追々調整します。player_raceの構造体は以下の通りです。

typedef struct player_race player_race;

struct player_race
{
	cptr title;			/* Type of race */

#ifdef JP
	cptr E_title;		/* 英語種族 */
#endif
	s16b r_adj[6];		/* Racial stat bonuses */

	s16b r_dis;			/* disarming */
	s16b r_dev;			/* magic devices */
	s16b r_sav;			/* saving throw */
	s16b r_stl;			/* stealth */
	s16b r_srh;			/* search ability */
	s16b r_fos;			/* search frequency */
	s16b r_thn;			/* combat (normal) */
	s16b r_thb;			/* combat (shooting) */

	byte r_mhp;			/* Race hit-dice modifier */
	byte r_exp;			/* Race experience factor */

	byte b_age;			/* base age */
	byte m_age;			/* mod age */

	byte m_b_ht;		/* base height (males) */
	byte m_m_ht;		/* mod height (males) */
	byte m_b_wt;		/* base weight (males) */
	byte m_m_wt;		/* mod weight (males) */

	byte f_b_ht;		/* base height (females) */
	byte f_m_ht;		/* mod height (females)	  */
	byte f_b_wt;		/* base weight (females) */
	byte f_m_wt;		/* mod weight (females) */

	byte infra;			/* Infra-vision	range */

	u32b choice;        /* Legal class choices */
/*    byte choice_xtra;   */
};

Legal class choicesだけ分かりづらいかもしれませんが、要は職業選択時に種族に向いている職業、を戦士から順に指定しているビット配列です。現状ステータス上には何の影響もないものですね。

んでもって、birth.cに種族の解説メッセージを追加します。とりあえず完全に仕様を確定するまでは仮メッセージを加えます。

+"アンドロイドは機(略)
+
+"マーフォーク実装中",

 #else

@@ -197,6 +199,8 @@ static cptr race_jouhou[MAX_RACES] =

 "An android is (略)

+"Merfolk implementing.",
+
 #endif
 };

ここまでは性格と全く同じ要領です。続けて、種族ごとに依存する項目として、生い立ちと、それに伴う社会的地位の変動設定などを加える必要がありますが、ひとまず今は一時人間と同じにしておきましょう。get_history()に以下のように加えます。

@@ -1277,6 +1281,7 @@ static void get_history(void)
 		case RACE_HUMAN:
 		case RACE_BARBARIAN:
 		case RACE_DUNADAN:
+		case RACE_MERFOLK:
 		{
 			chart = 1;
 			break;
diff --git a/src/defines.h b/src/defines.h

ここまでで、一度は走らせてみようとするとこうなります。

町情報がアレ

これは「辺境の地」の町データをまとめている/lib/edit/t0000001.txtの以下の部分の問題です。

B:$0:N:The White Horse Inn:Otick:Human
B:0:N:旅の宿『白馬亭』:オティック:人間
B:$0:A:0:Rest for the night:20:20:r:17:0
B:0:A:0:一泊する:20:20:r:17:0
B:$0:A:1:buy Food and drink:1:1:f:18:1
B:0:A:1:食事をする:1:1:f:18:1
B:$0:A:2:Listen for rumors:5:5:u:19:0
B:0:A:2:噂を聞く:5:5:u:19:0
B:$0:A:3:request Quest:0:0:q:6:0
B:0:A:3:クエスト:0:0:q:6:0
B:$0:A:4:Teleport to other town:500:500:m:42:0
B:0:A:4:他の町へ移動:500:500:m:42:0
B:$0:R:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:0:0:0:0:0:1:1:0:1:0:1:1:1:0
B:0:R:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:1:0:0:0:0:0:1:1:0:1:0:1:1:1:0

一番最後の行です。宿で、アンデッドやバルログなどが魔道具のエネルギーや血やら死体やらを売ってもらえない制限処理に該当する部分が、今回のマーフォークの追加に伴って、スロットが一つ増えたため、「引数不足」になってしまった次第です。このまま進めると恐ろしいバグで強制終了し、再起動しても町が消滅したりするというギャグみたいな状態になります。

ではこれを直していこうということで続きは次回。




2018/12/07

[変愚蛮怒/開発]変愚蛮怒開発日誌part99…特別編「変愚蛮怒の性格実装例 ~かわいそうなお友達~」

はじめに

変愚蛮怒がまさにソースコードの違法建築物であり、拡張に色々手を付けづらいのは事実なのですが、その中でも「性格」の実装はまだしも追加しないといけない処理が少なく、比較的手軽に実装が出来るのもまた確かです。

という訳で今回は全く趣味に走り、某超個性派レトロアニメの要素をモンスターだけでなくプレイヤー側に実現する手順を見てみましょう。

このネタは今や停滞して久しい拙バリアントD'angの旧ソースにも一応組み込んだことのあるものです。

ブランチ

という訳でOSDNのリポジトリにこんなブランチを作りました。今回は本当に即興なので、本流には調整やデバッグ済ませてからマージします。

基礎ステータス設定

まず特に最低限の部分だけ済ませましょう。性格のステータス修正を追加します。

defines.hにある性格の定義数を直しIDを定義します。

diff --git a/src/defines.h b/src/defines.h
index ec8e7db..4cf51fe 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -181,7 +181,7 @@
 #define MAX_OWNERS      32 /*!< 各店舗毎の店主定義最大数 / Total number of owners per store (see "store.c", etc) */
 #define MAX_SEXES        2 /*!< 性別の定義最大数 / Maximum number of player "sex" types (see "table.c", etc) */
 #define MAX_CLASS       28 /*!< 職業の最大定義数 Maximum number of player "class" types (see "table.c", etc) */
-#define MAX_SEIKAKU     12 /*!< 性格の最大定義数 */
+#define MAX_SEIKAKU     13 /*!< 性格の最大定義数 */
 #define MAX_PATRON      16 /*!< カオスパトロンの最大定義数 / The number of "patrons" available (for Chaos Warriors) */

 /* ELDRITCH_HORRORによるsanity blast処理に関するメッセージの最大数 / Number of entries in the sanity-blast descriptions */
@@ -825,6 +825,7 @@
 #define SEIKAKU_LUCKY	 9
 #define SEIKAKU_GAMAN	 10
 #define SEIKAKU_MUNCHKIN 11
+#define SEIKAKU_CHARGEMAN 12

tables.cにある性格ステータス修正テーブルにも追加します。seikaku_info構造体は以下の通りです。

typedef struct player_seikaku player_seikaku;
struct player_seikaku
{
	cptr title;			/* Type of seikaku */

#ifdef JP
	cptr E_title;		/* 英語性格 */
#endif

	s16b a_adj[6];		/* seikaku stat bonuses */

	s16b a_dis;			/* seikaku disarming */
	s16b a_dev;			/* seikaku magic devices */
	s16b a_sav;			/* seikaku saving throw */
	s16b a_stl;			/* seikaku stealth */
	s16b a_srh;			/* seikaku search ability */
	s16b a_fos;			/* seikaku search frequency */
	s16b a_thn;			/* seikaku combat (normal) */
	s16b a_thb;			/* seikaku combat (shooting) */

	s16b a_mhp;			/* Race hit-dice modifier */

	byte no;			/* の */
	byte sex;			/* seibetu seigen */
};

大体、ちからじまんといのちしらずのメリットデメリットを足して極端にしてみました。

diff --git a/src/tables.c b/src/tables.c
index cbb707d..71ec372 100644
--- a/src/tables.c
+++ b/src/tables.c
@@ -3240,6 +3240,17 @@ const player_seikaku seikaku_info[MAX_SEIKAKU] =
 		 20, 40, 30, 10, 40, 40,  80, 80,
 		 15, 1, 0
 	},
+
+	{
+#ifdef JP
+		"チャージマン",
+#endif
+		"Chargeman",
+		{ 2,  -2,  -2,  0,  1,  -2 },
+		-7, 7, -5, -1, -2, -4, 15, 20,
+		-1, 0, 0
+	},
+
 };


--

最後にキャラメイク時の解説追加です。ガバガバ英語 ゆ る し て

diff --git a/src/birth.c b/src/birth.c
index 8a92971..2cbd48e 100644
--- a/src/birth.c
+++ b/src/birth.c
@@ -347,6 +347,8 @@ static cptr seikaku_jouhou[MAX_SEIKAKU] =

 "いかさまは、初心者の練習用の性格です。あらゆる能力が高くなっています。この性格を使えば勝利者になることは容易ですが、勝利しても全く自慢になりません。",

+"チャージマンは「こんなところ」に連れて行かれても仕方のない可愛そうなお友達なんDA。腕っ節やタフさはマンモス並みに強いのだけれど知能面はまるで駄目なのが分かるだろう?この性格は最初から気が狂っているので、混乱したり幻覚を見る心配がないのです。",
+
 #else

 "\"Ordinary\" is a personality with no special skills or talents, with unmodified stats and skills.",
@@ -372,7 +374,10 @@ static cptr seikaku_jouhou[MAX_SEIKAKU] =

 "A \"Patient\" person does things carefully.  Patient people have high constitution, and high resilience, but poor abilities in most other skills.  Also it directly influences your hit-points.",

-"\"munchkin\" is a personality for beginners.  It raises all your stats and skills.  With this personality, you can win the game easily, but gain little honor in doing so."
+"\"munchkin\" is a personality for beginners.  It raises all your stats and skills.  With this personality, you can win the game easily, but gain little honor in doing so.",
+
+"\ChargeMan\" is crazy killer. It render you powerfull strength and constitution, but poor intelligence.you are not confused and seen the illusion because this you go mad from the beginning.",
+
 #endif
 };

以上でこうして性格がキャラメイク時に指定できるまでは可能になります。

Chargeman1

基礎特性修正

続けて上記の馴レーションで解説している通り、頭が元からお詳しいので、混乱耐性と幻覚耐性を持たせてみます。

耐性などの付加は種族、職業、性格などを問わずxtra1.cのcalc_bonuses()で追加できます。

diff --git a/src/xtra1.c b/src/xtra1.c
index fcb013a..e708b2c 100644
--- a/src/xtra1.c
+++ b/src/xtra1.c
@@ -3860,10 +3860,17 @@ void calc_bonuses(void)

 	/* Sexy Gal */
 	if (p_ptr->pseikaku == SEIKAKU_SEXY) p_ptr->cursed |= (TRC_AGGRAVATE);
+
 	if (p_ptr->pseikaku == SEIKAKU_NAMAKE) p_ptr->to_m_chance += 10;
 	if (p_ptr->pseikaku == SEIKAKU_KIREMONO) p_ptr->to_m_chance -= 3;
 	if ((p_ptr->pseikaku == SEIKAKU_GAMAN) || (p_ptr->pseikaku == SEIKAKU_CHIKARA)) p_ptr->to_m_chance++;

+	if (p_ptr->pseikaku == SEIKAKU_CHARGEMAN)
+	{
+		p_ptr->to_m_chance += 5;
+		p_ptr->resist_conf = TRUE;
+	}
+
 	/* Lucky man */
 	if (p_ptr->pseikaku == SEIKAKU_LUCKY) p_ptr->muta3 |= MUT3_GOOD_LUCK;

--

それとは別に files.cのplayer_flags()関数でCコマンドで表示される処理も追加しなければなりません。

diff --git a/src/files.c b/src/files.c
index f27b2da..4c016d9 100644
--- a/src/files.c
+++ b/src/files.c
@@ -2588,6 +2588,8 @@ static void player_flags(BIT_FLAGS flgs[TR_FLAG_SIZE])

 	if (p_ptr->pseikaku == SEIKAKU_SEXY)
 		add_flag(flgs, TR_AGGRAVATE);
+	if (p_ptr->pseikaku == SEIKAKU_CHARGEMAN)
+		add_flag(flgs, TR_RES_CONF);
 	if (p_ptr->pseikaku == SEIKAKU_MUNCHKIN)
 	{
 		add_flag(flgs, TR_RES_BLIND);

幻覚耐性については、ゴーレムやアンデッドが出血を抑止されるのと同様、set_image()関数で常に値を0にする処理で実装しましょう。

diff --git a/src/effects.c b/src/effects.c
index 5f391f3..ef781a0 100644
--- a/src/effects.c
+++ b/src/effects.c
@@ -697,6 +697,7 @@ bool set_image(TIME_EFFECT v)
 	v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;

 	if (p_ptr->is_dead) return FALSE;
+	if (p_ptr->pseikaku == SEIKAKU_CHARGEMAN) v = 0;


 	/* Open */

以下のように@さん自身の先天的体質として表示されます。

Chargeman3

台詞変化

あの「コンバット」に劣らぬ個性なのですから台詞の変化も欲しい所、大体、PSEIKAKU_COMBATで見つかる処理から、チャージマン向けに使えそうなメッセージをつうずるっこみます。

diff --git a/src/bldg.c b/src/bldg.c
index f8d9975..0b57b9d 100644
--- a/src/bldg.c
+++ b/src/bldg.c
@@ -4353,6 +4353,7 @@ void do_cmd_quest(void)
 		if (!get_check(_("クエストに入りますか?", "Do you enter? "))) return;
 		if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
 			msg_print(_("『とにかく入ってみようぜぇ。』", ""));
+		else if(p_ptr->pseikaku == SEIKAKU_CHARGEMAN) msg_print("『全滅してやるぞ!』");
diff --git a/src/mspells4.c b/src/mspells4.c
index a0a31c3..d7f267f 100644
--- a/src/mspells4.c
+++ b/src/mspells4.c
@@ -229,6 +229,11 @@ void spell_RF4_DISPEL(MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)

 		if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
 			msg_print(_("やりやがったな!", ""));
+		else if ((p_ptr->pseikaku == SEIKAKU_CHARGEMAN))
+		{
+			if (randint0(2) == 0) msg_print(_("ジュラル星人め!", ""));
+			else msg_print(_("弱い者いじめは止めるんだ!", ""));
+		}

 		learn_spell(MS_DISPEL);
 	}
@@ -2267,7 +2272,12 @@ void spell_RF6_TELE_AWAY(MONSTER_IDX m_idx, MONSTER_IDX t_idx, int TARGET_TYPE)
 	{
 		if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
 			msg_print(_("くっそ~", ""));
-
+		else if ((p_ptr->pseikaku == SEIKAKU_CHARGEMAN))
+		{
+			if (randint0(2) == 0) msg_print(_("ジュラル星人め!", ""));
+			else msg_print(_("弱い者いじめは止めるんだ!", ""));
+		}
+
 		learn_spell(MS_TELE_AWAY);
 		teleport_player_away(m_idx, 100);
 	}
diff --git a/src/player-damage.c b/src/player-damage.c
index 77d850d..05e2ac0 100644
--- a/src/player-damage.c
+++ b/src/player-damage.c
@@ -300,6 +300,11 @@ int inven_damage(inven_func typ, int perc)
 #ifdef JP
 				if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
 					msg_print("やりやがったな!");
+				else if ((p_ptr->pseikaku == SEIKAKU_CHARGEMAN))
+				{
+					if (randint0(2) == 0) msg_print(_("ジュラル星人め!", ""));
+					else msg_print(_("弱い者いじめは止めるんだ!", ""));
+				}
 #endif

 				/* Potions smash open */
diff --git a/src/trap.c b/src/trap.c
index 9bb329f..5c93fdf 100644
--- a/src/trap.c
+++ b/src/trap.c
@@ -321,6 +321,9 @@ void hit_trap(bool break_trap)
 			msg_print(_("落とし戸に落ちた!", "You have fallen through a trap door!"));
 			if ((p_ptr->pseikaku == SEIKAKU_COMBAT) || (inventory[INVEN_BOW].name1 == ART_CRIMSON))
 				msg_print(_("くっそ~!", ""));
+			else if((p_ptr->pseikaku == SEIKAKU_CHARGEMAN))
+				msg_print(_("ジュラル星人の仕業に違いない!", ""));
+

Chargeman2

まあこんな感じに。

モンスター誤認

個人的にキチガイアニメらしい着想を考えてみました。何でもかんでもとりあえずジュラル星人として襲い掛かるマジキチぶりをモンスターを誤認する能力で表してみようと思います。

具体的には地上では100%、地下でも20%の確率で相手をジュラル星人と思い込ませることにしましょう。この実装は、現状の「あやしい影」や「たぬき」で実装済のモンスターの実IDと外見IDの分化仕様から簡単にできました。

---
 src/defines.h  | 1 +
 src/monster2.c | 6 +++++-
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/src/defines.h b/src/defines.h
index 4cf51fe..6955ce2 100644
--- a/src/defines.h
+++ b/src/defines.h
@@ -5119,6 +5119,7 @@ extern int PlayerUID;
 #define MON_WYRM_SPACE    1064
 #define MON_JIZOTAKO      1065
 #define MON_TANUKI        1067
+#define MON_ALIEN_JURAL   1082
 #define MON_HATOPOPPO     1083
 #define MON_KOGAN         1096

diff --git a/src/monster2.c b/src/monster2.c
index 38a07a6..a6d0059 100644
--- a/src/monster2.c
+++ b/src/monster2.c
@@ -2904,10 +2904,14 @@ static bool monster_hook_tanuki(MONRACE_IDX r_idx)
 static IDX initial_r_appearance(MONRACE_IDX r_idx)
 {
 	int attempts = 1000;
-
 	IDX ap_r_idx;
 	DEPTH min = MIN(base_level-5, 50);

+	if (p_ptr->pseikaku == SEIKAKU_CHARGEMAN)
+	{
+		if (base_level == 0 || one_in_(5)) return MON_ALIEN_JURAL;
+	}
+
 	if (!(r_info[r_idx].flags7 & RF7_TANUKI))
 		return r_idx;

Chargeman3

いやあ、絵になる頭のおかしさです。

最後に

いかがでしたでしょうか。これで参考になるならば是非色々いじってみてください。そんでもって、これを機に誰かソースコードのプルリクエストとかかましてくれませんかね……

ああ、ただ今後リファクタリングで修正を要する箇所が変化する可能性が……まあ分からんことがありましたらTwitterなどでご質問もどうぞ(震え声)