Elona改造講座 第16回(鍛冶ハンマーの移植:前編)

お久しぶりのElona改造講座です。
大規模な改造として、今回から2~3回かけてoo系列の鍛冶ハンマーの処理をMMAhに移植してみましょう。
 
最初にいくつか注意点があります。
・本講座で掲載するソースコードのラベル名はMMAhの20230113版(最新版)か20220121版(その1つ前の版)、およびCSの配布ソースに準拠しています。
 他のバージョン(CSのexeを逆コンパイルしたものも含む)だとラベル名がズレるのでご注意ください。
・本講座のソースコードには適宜コメントを追加しています。
 また、elseとifは1行にまとめた形に書き換えています。
 この為、逆コンパイルした直後のソースコードとは若干の違いがあります。


①鍛冶ハンマーとは?

ooで追加されたカスタムアイテムです。
最初は「ボロボロのハンマー」という名前で店売りされているだけのアイテムですが、これを使って武具の作成や修理を行うことでハンマーに経験値が溜まってレベルが上がっていき、やがて「丈夫なハンマー」や「鍛冶師のハンマー」などと名前が変化していき、AF合成や武具の強化などできることが増えていきます。
ここで「カスタムアイテムなのでMMAhに導入することもできるのでは?」と思う方もいるでしょう。実際に導入自体は可能で、導入することで雑貨屋や何でも屋に売り出されもするのですが、いざ使ってみるとこの通り。効果が設定されていない為「それはomake_MMA/TrashThrowでは使用できない」と表示されるだけです。

店売りされているハンマーを購入してみましたが使用はできません

ソースコードのハンマーの処理(_switch_val == 2000)を見てみても、警告メッセージが出るだけで特に効果は設定されていませんね。

ハンマーには効果が設定されていません

②ooから移植すべき処理を特定

まずはooのソースコードの_switch_val == 2000を見てみましょう。*label_2831にジャンプする処理が見つかりますね。
(*label_2202は全アイテム共通の終了処理ようなので今は忘れておきましょう)
ccが0でない場合(すなわちPC以外が使用した場合)には無視するような安全措置も入っているようです。

// 鍛冶ハンマーを使用
if ( _switch_val == 2000 | _switch_sw ) {
	_switch_sw = 0
	if ( cc != 0 ) {
		txtvalid = 0
		txt_select lang("何もおきない… ", "Nothing happens..."), "", "", "", "", "", "", "", ""
		goto *label_2202
	}
	cw = ci
	snd 100
	gosub *label_2831
	if ( stat ) {
		extend = 0
		cdata(140, cc) = 20012
		cdata(141, cc) = 25 + rnd(11)
		cdata(142, cc) = cw
	}
	else {
		obvious = 0
	}
	goto *label_2202
	_switch_sw++
}
ooではハンマー使用時に*label_2831にジャンプします

続いて"鍛冶の技術が足りない。"で検索してみましょう。
(Lv20以下のハンマーでAF合成許可証を使用した時のメッセージです)
*label_2831が見つかりましたね。これがooにおける鍛冶の処理のメインであり、鍛冶ハンマー使用時にはまずこのラベルにジャンプすることになります。溶鉱炉と金床があるかどうかを確認したり、作る武器の種別を選択する処理などが書かれているようです。

*label_2831
	invsubroutine = 1
	dim craftref, 10
	invctrl = 30, 0
	step = 0
	cancel = 0
	cdata(144, cc) = 0
	repeat
		if ( cdata(144, cc) != 0 ) {
			if ( cdata(144, cc) == 3 ) {
				gosub *label_2833
				if ( stat == 0 ) {
					cancel = 1
				}
			}
			break
		}
		if ( cancel ) {
			break
		}
		gosub *label_2030
		if ( stat == 1 ) {
			reftypeminor = refitem(inv(3, ci), 9, ci)
			if ( step == 0 ) {
				// 武器の作成 折れた刃(ID:50)が必要
				if ( inv(3, ci) == 50 ) {
					anvil = 0
					furnance = 0
					repeat 5480
						// 金床(ID:96)と溶鉱炉(ID:531)がマップ内にあることの確認
						if ( anvil & furnance ) {
							break
						}
						if ( inv(0, cnt) <= 0 ) {
							continue
						}
						if ( inv(3, cnt) == 96 ) {
							anvil = 1
						}
						else {
							if ( inv(3, cnt) == 531 ) {
								furnance = 1
							}
						}
					loop
					if ( anvil == 0 | furnance == 0 ) {
						txtvalid = 0
						txt_select lang("溶鉱炉と金床が必要だ。", "furnace and anvil required."), "", "", "", "", "", "", "", ""
						cancel = 1
						break
					}
					txtef 5
					txtvalid = 0
					txt_select lang("何を作る?", "What do you create? "), "", "", "", "", "", "", "", ""
					promptl(0, promptmax) = lang("大剣", "Repair"), "a", "" + 1
					promptmax++
					promptl(0, promptmax) = lang("長剣", "Repair"), "b", "" + 2
					promptmax++
					promptl(0, promptmax) = lang("短剣", "Repair"), "c", "" + 3
					promptmax++
					promptl(0, promptmax) = lang("槍", "Repair"), "d", "" + 7
					promptmax++
					promptl(0, promptmax) = lang("鉾槍", "Repair"), "e", "" + 8
					promptmax++
					promptl(0, promptmax) = lang("斧", "Repair"), "f", "" + 9
					promptmax++
					promptl(0, promptmax) = lang("大斧", "Repair"), "g", "" + 10
					promptmax++
					promptl(0, promptmax) = lang("鎌", "Repair"), "h", "" + 11
					promptmax++
					val = promptx, prompty, 220, 1
					gosub *label_2103
					if ( rtval == (-1) ) {
						cancel = 1
						break
					}
					craftref(step * 2) = -1, 10000 + rtval
					step++
					invctrl(1) = 1
				}
				else {
					// AF合成 AF合成許可証が必要 ハンマーLv21以上必要
					if ( equalsitem(ci, "artifacts fusion license") ) {
						if ( inv(25, cw) <= 20 ) {
							txtvalid = 0
							txt_select lang("鍛冶の技術が足りない。", "smith's skill is lacking."), "", "", "", "", "", "", "", ""
							cancel = 1
							break
						}
<以下省略>
*label_2831が鍛冶の処理のメインとなる部分です

鍛冶の処理はこれ以降にも続いており、label_2831~label_2835が鍛冶の処理に関係したサブルーチンとなります。各サブルーチンの内訳は次のようになります。

label_2831
 鍛冶の処理のメイン
 (鍛冶ハンマー選択時に最初に呼ばれるサブルーチン)
 
label_2832
 鍛冶のオートターン処理
 (鍛冶の途中でカキーンとか表示されるやつ)
 (結果のアイテム生成処理もここ)
 
*label_2833
 AF合成の処理
 
*label_2834
 AF合成、継承エンチャ一覧のページ送り
 
*label_2835
 AF合成、継承エンチャ一覧表示処理
 (決定キーでAF合成開始)
 

また、これらとは別に鍛冶で使用する専用の関数も存在します。
当然ながらこれらも移植する必要があります。

getencplimit
 AF合成のエンチャント強度限界の取得処理
 
modexpsmith
 鍛冶ハンマーの経験値獲得処理
 
smithcheck
 アイテムが鍛冶に使えるか否かのチェック処理
 (「鍛えるアイテム」の欄に表示されるアイテムをリストアップする為の処理)
 
reinforcecheck
 会心の出来・自信作の場合の処理
鍛冶専用の関数もあります

③移植の方針

以上の処理をooからMMAhに移植していきます。従来通りにstart.hspに追加してもかまわないのですが、今回は別ファイルに記述する方式を取ってみましょう。
まずstart.hspと同じフォルダに「cs_smith.hsp」という名前の空のファイルを作成してください。次にstart.hsp内を"どのファイルから神を作成する?"で検索し、出てきたラベル*label_1354の上に以下のように記述してください。

// CS追加 鍛冶ハンマーの処理(別ファイル)のインクルード
#include "cs_smith.hsp"

#includeは指定したソースファイル(ここではcs_smith.hsp)の内容をこの位置に埋め込むことを意味します。
(別にこの位置でincludeする必要はありませんが、移植元のooと揃える為にここでやっています)
以降はこのファイルのみを加筆していきます。

cs_smith.hspをincludeしました
鍛冶の処理は全てこのcs_smith.hspの中に記述します

ooからの移植後には、主に以下の変更を加える必要があります。
(1)鍛冶専用の変数・配列の宣言を追加
 (無いとコンパイル時に弾かれます)
(2)テキスト表示方式の変更への対応
 (txt_selectの第1引数に-1を追加します。また、txtvalid = 0やtxtmoreは削除します)
(3)ジャンプ先ラベルの書き換え
 (鍛冶関係の場合はlabel_XXXXをlabel_smith_XXXXに変更します。それ以外のラベルの場合は処理内容から判断して対応するラベルを特定し、そこに飛びます)

この中で一番面倒なのは(3)のジャンプ先ラベルの書き換えです。
ooとMMAhでラベル番号の対応を取らないといけませんので……
ですが今回は私が既に対応を取ってしまっているので、ただ書き換えるだけでOKです。

④*label_2831の移植

まずはooのlabel_2831を移植します。cs_smith.hspにlabel_smith_2831という名前で移植しましょう。
移植後の*label_smith_2831は次のようになります。
ジャンプ先を書き換えたラベルは3種4箇所です。
label_2833はAF合成処理です。後で移植するのでlabel_smith_2833に書き換えておきましょう。
label_2030はインベントリ内のアイテム選択のサブルーチンです。MMAhではlabel_0936にあたります。
label_2103は選択肢を表示するサブルーチンです。MMAhではlabel_0992に相当します。作る武器・防具の種別を選択する為に使用します。

/* 鍛冶の処理 メイン */
*label_smith_2831
	// CS追加 鍛冶に使用する変数の宣言(未初期化対策)
	dim fusionlist, 2, 15
	fusionlistmax = 0

	invsubroutine = 1
	dim craftref, 10
	invctrl = 30, 0
	step = 0
	cancel = 0
	cdata(144, cc) = 0
	repeat
		if ( cdata(144, cc) != 0 ) {
			if ( cdata(144, cc) == 3 ) {
//				gosub *label_2833
				gosub *label_smith_2833
				if ( stat == 0 ) {
					cancel = 1
				}
			}
			break
		}
		if ( cancel ) {
			break
		}
		// インベントリ内のアイテム選択
		// CS追加 本来はlabel_2030でcc=0にしてそのまま*label_2031に入る
		// CSではcc=0してから*label_0936に移動
//		gosub *label_2030
		cc = 0
		gosub *label_0936
		if ( stat == 1 ) {
			reftypeminor = refitem(inv(3, ci), 9, ci)
			if ( step == 0 ) {
				// 武器の作成 折れた刃(ID:50)が必要
				if ( inv(3, ci) == 50 ) {
					anvil = 0
					furnance = 0
					repeat 5480
						// 金床(ID:96)と溶鉱炉(ID:531)がマップ内にあることの確認
						if ( anvil & furnance ) {
							break
						}
						if ( inv(0, cnt) <= 0 ) {
							continue
						}
						if ( inv(3, cnt) == 96 ) {
							anvil = 1
						}
						else : if ( inv(3, cnt) == 531 ) {
							furnance = 1
						}
					loop
					if ( anvil == 0 | furnance == 0 ) {
						txt_select -1, lang("溶鉱炉と金床が必要だ。", "furnace and anvil required."), "", "", "", "", "", "", "", ""
						cancel = 1
						break
					}
					txtef 5
					txt_select -1, lang("何を作る?", "What do you create? "), "", "", "", "", "", "", "", ""
					promptl(0, promptmax) = lang("大剣", "Repair"), "a", "" + 1
					promptmax++
					promptl(0, promptmax) = lang("長剣", "Repair"), "b", "" + 2
					promptmax++
					promptl(0, promptmax) = lang("短剣", "Repair"), "c", "" + 3
					promptmax++
					promptl(0, promptmax) = lang("槍", "Repair"), "d", "" + 7
					promptmax++
					promptl(0, promptmax) = lang("鉾槍", "Repair"), "e", "" + 8
					promptmax++
					promptl(0, promptmax) = lang("斧", "Repair"), "f", "" + 9
					promptmax++
					promptl(0, promptmax) = lang("大斧", "Repair"), "g", "" + 10
					promptmax++
					promptl(0, promptmax) = lang("鎌", "Repair"), "h", "" + 11
					promptmax++
					val = promptx, prompty, 220, 1
//					gosub *label_2103
					gosub *label_0992
					if ( rtval == (-1) ) {
						cancel = 1
						break
					}
					craftref(step * 2) = -1, 10000 + rtval
					step++
					invctrl(1) = 1
				}
				else {
					// AF合成 AF合成許可証が必要 ハンマーLv21以上必要
					if ( equalsitem(ci, "artifacts fusion license") ) {
						if ( inv(25, cw) <= 20 ) {
							txt_select -1, lang("鍛冶の技術が足りない。", "smith's skill is lacking."), "", "", "", "", "", "", "", ""
							cancel = 1
							break
						}
						anvil = 0
						furnance = 0
						repeat 5480
							// 金床(ID:96)と溶解炉(ID:111)がマップ内にあることの確認
							if ( anvil & furnance ) {
								break
							}
							if ( inv(0, cnt) <= 0 ) {
								continue
							}
							if ( inv(3, cnt) == 96 ) {
								anvil = 1
							}
							else : if ( inv(3, cnt) == 111 ) {
								furnance = 1
							}
						loop
						if ( anvil == 0 | furnance == 0 ) {
							txt_select -1, lang("溶解炉と金床が必要だ。", "furnace and anvil required."), "", "", "", "", "", "", "", ""
							cancel = 1
							break
						}
						txtnew
						txt_select -1, lang("まずは土台となるアーティファクトを選ぶ必要がある。", "Choose an base."), "", "", "", "", "", "", "", ""
						invctrl(1) = 2
					}
					else {
						// 防具の作成 皮(ID:337)が必要
						if ( inv(3, ci) == 337 ) {
							anvil = 0
							furnance = 0
							repeat 5480
								// 金床(ID:96)と溶解炉(ID:111)がマップ内にあることの確認
								if ( anvil & furnance ) {
									break
								}
								if ( inv(0, cnt) <= 0 ) {
									continue
								}
								if ( inv(3, cnt) == 96 ) {
									anvil = 1
								}
								else : if ( inv(3, cnt) == 111 ) {
									furnance = 1
								}
							loop
							if ( anvil == 0 | furnance == 0 ) {
								txt_select -1, lang("溶解炉と金床が必要だ。", "furnace and anvil required."), "", "", "", "", "", "", "", ""
								cancel = 1
								break
							}
							txtef 5
							txt_select -1, lang("何を作る?", "What do you create? "), "", "", "", "", "", "", "", ""
							promptl(0, promptmax) = lang("鎧", "Armor"), "a", "" + 16001
							promptmax++
							promptl(0, promptmax) = lang("兜", "Helmet"), "b", "" + 12001
							promptmax++
							promptl(0, promptmax) = lang("盾", "Shild"), "c", "" + 14003
							promptmax++
							promptl(0, promptmax) = lang("重靴", "Heavy boots"), "d", "" + 18001
							promptmax++
							promptl(0, promptmax) = lang("ガントレット", "Gauntlets"), "e", "" + 22001
							promptmax++
							val = promptx, prompty, 220, 1
//							gosub *label_2103
							gosub *label_0992
							if ( rtval == (-1) ) {
								cancel = 1
								break
							}
							craftref(step * 2) = -1, rtval
							step++
							cdata(144, cc) = 4
						}
						else {
							notfound = 1
							// 装備の修理・強化
							if ( inv(20, ci) < 0 ) {
								// 装備の修理 無条件に実行可能
								notfound = 0
							}
							else {
								anvil = 0
								repeat 5480
									if ( inv(0, cnt) <= 0 ) {
										continue
									}
									if ( inv(3, cnt) == 96 ) {
										anvil = 1
										break
									}
								loop
								if ( anvil == 0 ) {
									txt_select -1, lang("金床が必要だ。", "anvil required."), "", "", "", "", "", "", "", ""
									cancel = 1
									break
								}
								// 装備の強化 ハンマーLv21以上必要 ハンマーLv/7まで強化可能
								if ( inv(25, cw) >= 21 & inv(20, ci) < inv(25, cw) / 7 ) {
									notfound = 0
								}
							}
							if ( notfound ) {
								txt_select -1, lang("鍛冶の必要はない。", "It is not necessary to fix."), "", "", "", "", "", "", "", ""
								cancel = 1
								break
							}
							cdata(144, cc) = 2
						}
					}
				}
			}
			else {
				if ( step == 1 ) {
					reftype = refitem(inv(3, ci), 5, ci)
					if ( inv(4, ci) >= 4 & inv(4, ci) <= 5 & reftype >= 10000 & reftype <= 50000 ) {
						txtnew
						txt_select -1, lang("エンチャントを継承するアーティファクトを選ぶ必要がある。このアーティファクトは合成後、永久に失われる。", "Choose a artifact. Once you extract a enchant, the subject will be lost forever."), "", "", "", "", "", "", "", ""
						snd 100
						invctrl(1) = 2
					}
				}
				else {
					if ( step == 2 ) {
						reftype = refitem(inv(3, ci), 5, ci)
						if ( reftypeminor == 77001 | inv(3, ci) == 337 | inv(3, ci) == 716 ) {
							cdata(144, cc) = 1
						}
						else {
							if ( inv(4, ci) >= 4 & inv(4, ci) <= 5 & reftype >= 10000 & reftype <= 50000 ) {
								if ( ibit(13, ci) ) {
									snd 27
									txt_select -1, lang("それはあなたの大事なものだ。<調べる>メニューから解除できる。", "It's set as no-drop. You can reset it from the <examine> menu."), "", "", "", "", "", "", "", ""
									continue
								}
								cdata(144, cc) = 3
							}
						}
					}
				}
			}
			craftref(step * 2) = ci, inv(3, ci)
			step++
		}
		else {
			cancel = 1
		}
	loop
	if ( cancel ) {
		return 0
	}
	return 1

⑤*label_2832の移植

鍛冶のオートターン処理です。txt_selectとジャンプ先ラベルの変更箇所が多いです。 
label_0277は素材に応じて価値を決定する処理で、MMAhではlabel_0241にあたります。
label_1960は銘(異名)の選択処理です。MMAhではlabel_0888にあたります。
label_1441は能力の再計算でしょうか? MMAhではlabel_0515にあたります。
label_1480は所持重量の再計算のようです。MMAhではlabel_0553にあたります。

/* 鍛冶 オートターン処理 MMAhでは*label_1182から呼び出される */
*label_smith_2832
	if ( cdata(141, cc) \ 6 == 0 ) {
		actionsp cc, 2
		if ( stat == 0 ) {
			txt_select -1, lang("疲労し過ぎて失敗した!", "You are too exhausted!"), "", "", "", "", "", "", "", ""
			rowactend cc
			return
		}
	}
	if ( cdata(141, cc) > 0 ) {
		if ( rnd(5) == 0 ) {
			txtef 4
			txt_select -1, lang(" *カキーン* ", "*bang*"), lang(" *カーン* ", "*bang*"), "", "", "", "", "", "", ""
		}
		if ( cdata(144, cc) == 1 | cdata(144, cc) == 4 ) {
			if ( rnd(40 + extend * 10) == 0 ) {
				extend++
			}
		}
		return
	}
	cw = cdata(142, cc)
	if ( cdata(144, cc) == 1 | cdata(144, cc) == 4 ) {
		quality = 0
		repeat step - 1, 1
			ci = craftref(cnt * 2)
			quality += inv(1, ci)
			inv(0, ci)--
		loop
		randomize inv(25, cw) * 1000000 + inv(26, cw)
		exrand_randomize inv(25, cw) * 1000000 + inv(26, cw)
		if ( powf(inv(25, cw), 3) + sdata(11, cc) * 5 < rnd(quality) ) {
			txtef 3
			txt_select -1, lang("作成に失敗した……", "The blending attempt failed..."), "", "", "", "", "", "", "", ""
			modexpsmith cw, 1 + rnd(limit(10 / inv(25, cw), 1, 2147483647)) + limitmax(inv(27, cw), quality / 1000)
			inv(27, cw)++
			skillexp2 11, cc, 10
			randomize
			exrand_randomize
			return
		}
		flt inv(25, cw)
		flttypeminor = craftref(1)
		if ( cdata(144, cc) == 4 ) {
			ci = craftref(2)
		}
		else {
			ci = craftref(4)
		}
		reftypeminor = refitem(inv(3, ci), 9, ci)
		if ( inv(3, ci) == 716 ) {
			fltmaterial = 31 // アダマンタイト製
			fixlv = calcfixlv(limit(inv(25, cw) * 2 / 25, 1, 4))
		}
		else {
			if ( reftypeminor == 77001 ) {
				if ( inv(3, ci) == 42 ) {
					fltmaterial = 13 // ダイヤ製
				}
				else : if ( inv(3, ci) == 41 ) {
					fltmaterial = 23 // エメラルド製
				}
				else : if ( inv(3, ci) == 40 ) {
					fltmaterial = 21 // ミカ製
				}
				else : if ( inv(3, ci) == 39 ) {
					fltmaterial = 15 // ルビナス製
				}
				refvalue = refitem(inv(3, ci), 20, ci)
				fixlv = calcfixlv(limit(quality / (refvalue * powf(11, 2) / limitmin(inv(25, cw) * 2 / 25, 1)), 1, 4))
			}
			else {
				if ( inv(3, ci) == 337 ) {
					s = refchara(inv(23, ci), 8, 1)
					if ( instr(s, 0, "/dragon/") != (-1) ) {
						fltmaterial = 24 // ドラゴン類の場合、竜鱗製
					}
					else : if ( inv(23, ci) == 134 ) {
						fltmaterial =  9 // スティールゴーレムの場合、スティール製
					}
					else : if ( inv(23, ci) == 135 | inv(23, ci) == 112 ) {
						fltmaterial = 32 // ゴールドゴーレムorゴールデンアーマーの場合、ゴールデン製
					}
					else : if ( inv(23, ci) == 136 ) {
						fltmaterial =  7 // ミスリルゴーレムの場合、ミスリル製
					}
					else : if ( inv(23, ci) == 138 ) {
						fltmaterial = 31 // アダマンタイトゴーレムの場合、アダマンタイト製
					}
					else : if ( inv(23, ci) == 110 ) {
						fltmaterial = 12 // リビングアーマーの場合、ブロンズ製
					}
					else : if ( inv(23, ci) == 111 ) {
						fltmaterial = 10 // 鉄塊の場合、鉄製
					}
					else : if ( inv(23, ci) == 113 ) {
						fltmaterial = 29 // デスアーマーの場合、チタン製
					}
					else : if ( inv(23, ci) == 191 | inv(23, ci) == 193 ) {
						fltmaterial =  8 // ウィスプor輝くハリねずみの場合、エーテル製
					}
					else {
						fltmaterial =  4 // 上記以外は鱗製
					}
					refvalue = refitem(inv(3, ci), 20, ci)
					fixlv = calcfixlv(limit(quality / (refvalue * 20 / limitmin(inv(25, cw) * 2 / 25, 1)), 1, 4))
				}
			}
		}
		// 神器品質は奇跡品質に
		if ( fixlv > 4 ) {
			fixlv = 4
		}
		nostack = 1
		mode = 8
		itemcreate -1, 0, cdata(1, 0), cdata(2, 0), 0
		mode = 0
		inv(8, ci) = 3
		fixmaterial = fltmaterial
		fltmaterial = 0
		// 素材に応じて価値を決定
//		gosub *label_0277
		gosub *label_0241
		expsmith = rnd(limit(quality - powf(inv(25, cw), 3), 1, 2147483647)) + limitmax(inv(27, cw), quality / 1000)
		if ( extend ) {
			if ( inv(4, ci) >= 3 ) {
				if ( rnd(40 / limitmax(extend, 40)) <= gettrait(cc, 70) * 3 ) {
					txt_select -1, lang("これは会心の出来だ!", "Critical!"), "", "", "", "", "", "", "", ""
					//txtmore
					repeat 15
						p = reinforcecheck(cnt, ci)
						if ( p == (-1) ) {
							break
						}
						if ( p ) {
							inv(41 + cnt * 2, ci) += p * 3 / 2
						}
					loop
					ibitmod 17, ci, 1
				}
				else {
					if ( rnd(10 / limitmax(extend, 10)) <= gettrait(cc, 70) * 3 ) {
						txt_select -1, lang("これは自信作だ!", "Confident of the merits!"), "", "", "", "", "", "", "", ""
						//txtmore
						repeat 15
							p = reinforcecheck(cnt, ci)
							if ( p == (-1) ) {
								break
							}
							if ( p ) {
								inv(41 + cnt * 2, ci) += p / 2
							}
						loop
						ibitmod 17, ci, 1
					}
				}
			}
		}
		randomize
		exrand_randomize
		if ( inv(4, ci) == 4 ) {
			txtef 4
			txt_select -1, lang("銘は?", "What do you want to name this artifact?"), "", "", "", "", "", "", "", ""
			val = 3
			// 銘(異名)の選択
//			gosub *label_1960
			gosub *label_0888
			if ( stat ) {
				p = stat
				inv(23, ci) = list(1, p) + 40000
				randomize
			}
			else {
				obvious = 0
				randomize
			}
		}
		txtef 2
		txt_select -1, lang(itemname(ci, 1) + "の作成に成功した!", "You successfully create " + itemname(ci, 1) + "!"), "", "", "", "", "", "", "", ""
		snd 58
		modexpsmith cw, expsmith
		inv(27, cw)++
		skillexp2 11, cc, 50
	}
	else {
		if ( cdata(144, cc) == 2 ) {
			ci = craftref(0)
			txtef 2
			if ( inv(20, ci) < 0 ) {
				txt_select -1, lang(itemname(ci) + "の修理を終えた。", "Repair of " + itemname(ci) + " was finished."), "", "", "", "", "", "", "", ""
			}
			else {
				txt_select -1, lang(itemname(ci) + "を打ち直した。", "Upgrade of " + itemname(ci) + " was finished."), "", "", "", "", "", "", "", ""
			}
			snd 58
			inv(20, ci)++
			modexpsmith cw, 1 + rnd(limitmin(10 / inv(25, cw), 1))
			skillexp2 11, cc, 50
			r1 = cc
//			gosub *label_1441
			gosub *label_0515
		}
		else {
			if ( cdata(144, cc) == 3 ) {
				olist = craftref(0), craftref(4)
				repeat 2
					inv(0, olist(cnt))--
					chara_unequip olist(cnt)
					cell_refresh inv(5, olist(cnt)), inv(6, olist(cnt))
				loop
				ci = craftref(2)
				repeat fusionlistmax
					encadd ci, fusionlist(0, cnt), fusionlist(1, cnt), 0, 1
				loop
				txtef 2
				txt_select -1, lang("合成完了!", "You successfully fusion!"), "", "", "", "", "", "", "", ""
				snd 58
				modexpsmith cw, 1 + rnd(limitmin(2000 / inv(25, cw), 1)) + limitmax(inv(27, cw), quality / 1000)
				inv(27, cw)++
				skillexp2 11, cc, 250
				// 所持重量計算
//				gosub *label_1480
				gosub *label_0553
				r1 = 0
//				gosub *label_1441
				gosub *label_0515
			}
		}
	}
	return

⑥*label_2833の移植

AF合成の処理です。label_0259はエンチャ名を表示するサブルーチンです。MMAhではlabel_0227に相当します。
これとtxt_selectが1箇所あるだけで、それ以外には特に変更の必要は無さそうですね。
(実はここには1つ大きな落とし穴があるのですが、それについてはまたいずれ……)

/* 鍛冶 AF合成の処理 */
*label_smith_2833
	gsel 4
	repeat 8
		pos cnt \ 4 * 180, cnt / 4 * 300
		picload exedir + "\\graphic\\g" + (cnt + 1) + ".bmp", 1
	loop
	gsel 0
	listmax = 0
	page = 0
	pagesize = 14
	cs = 0
	cc = 0
	cs_bk = -1
	inhmax = 0
	inh_ci = craftref(4)
	getinheritance inh_ci, inhlist, inhmax
	if ( stat == 0 ) {
		txt_select -1, lang("部屋が一杯で出来ない。", "Your home has no empty spot."), "", "", "", "", "", "", "", ""
		return 0
	}
	base_ci = craftref(2)
	repeat inhmax
		encno = inhlist(cnt)
		val = inv(40 + encno * 2, inh_ci)
		if ( inv(25, cw) <= 40 ) {
			p(65) = val / 10000
			if ( p(65) == 0 ) {
				p(65) = val
			}
			if ( p(65) == 53 | p(65) == 34 ) {
				continue
			}
			if ( encref(0, p(65)) > 2 + (inv(25, cw) > 30) ) {
				continue
			}
		}
		val(1) = limitmax(inv(41 + encno * 2, inh_ci), getencplimit(val(0)))
		p(59) = 0
		encpmax = inv(25, cw) / 10 * getencplimit(val(0))
		repeat 15
			if ( inv(40 + cnt * 2, base_ci) == 0 ) {
				break
			}
			if ( inv(40 + cnt * 2, base_ci) == val(0) ) {
				if ( inv(41 + cnt * 2, base_ci) + val(1) > encpmax ) {
					p(59) = 1
					break
				}
			}
		loop
		if ( p(59) ) {
			continue
		}
		val(2) = 0, refitem(inv(3, inh_ci), 5, inh_ci)
		strict = 1
		// エンチャント名の表示 MMAhでは*label_0227に相当
//		gosub *label_0259
		gosub *label_0227
		strict = 0
		list(0, listmax) = val(0), val(1)
		listn(0, listmax) = cnven(s)
		listmax++
	loop
	if ( listmax == 0 ) {
		list(0, listmax) = -1
		listn(0, listmax) = "継承効果なし"
		listmax++
	}
	windowshadow = 1

このサブルーチンの末尾にはreturnが無い為、末尾まで来るとそのまま次のラベルに進みます。

⑦*label_2834の移植

継承エンチャ一覧のページ送り機能です。これは最初のラベル名以外に変更が必要な部分は無さそうですね。これもreturn無しのサブルーチンです。

/* 鍛冶 AF合成 ページ送り */
*label_smith_2834
	redraw 0
	cs_bk = -1
	pagemax = (listmax - 1) / pagesize
	if ( page < 0 ) {
		page = pagemax
	}
	else {
		if ( page > pagemax ) {
			page = 0
		}
	}

⑧*label_2835の移植

ここもほぼ変更の必要は無さそうです。ジャンプ先ラベル名は変更していますが、このラベル自身か前章のラベルかしかないので、"_smith"を付けるだけで特に迷う要素はありませんね。

/* 鍛冶 AF合成 継承エンチャ一覧表示 */
*label_smith_2835
	redraw 0
	s = lang("継承されるエンチャント", "Inheritance enchants."), lang("決定 [開始]  ", "Enter [Start] ") + strhint2 + strhint3b
	display_window (windoww - 500) / 2 + inf_screenx, winposy(400), 500, 400
	x = ww / 5 * 3
	y = wh - 80
	gmode 4, 180, 300, 50
	pos wx + ww / 3 * 2, wy + wh / 2
	grotate 4, cmbg / 4 \ 4 * 180, cmbg / 4 / 4 \ 2 * 300, 0, x, y
	gmode 2
	display_topic lang("継承効果", "Inheritance effects"), wx + 28, wy + 36
	keyrange = 0
	repeat pagesize
		p = pagesize * page + cnt
		if ( p >= listmax ) {
			break
		}
		key_list(cnt) = key_select(cnt)
		keyrange++
		if ( cnt \ 2 == 0 ) {
			pos wx + 70, wy + 66 + cnt * 19
			gfini ww - 100, 18
			gfdec2 12, 14, 16
		}
	loop
	gmode 2
	font lang(cfg_font1, cfg_font2), 14 - en * 2, 0
	cs_listbk
	repeat pagesize
		p = pagesize * page + cnt
		if ( p >= listmax ) {
			break
		}
		i = list(0, p)
		s = "" + listn(0, p)
		cs_list s, wx + 58, wy + 66 + cnt * 19 - 1, 19
	loop
	if ( keyrange != 0 ) {
		cs_bk = cs
	}
	redraw 1
	await cfg_wait1
	key_check
	if ( key == key_enter ) {
		if ( i == (-1) ) {
			return 0
		}
		// 継承エンチャを配列fusionlistにセット
		repeat listmax
			fusionlist(0, cnt) = list(0, cnt)
			fusionlist(1, cnt) = list(1, cnt)
		loop
		fusionlistmax = listmax
		return 1
	}
	cursor_check
	if ( key == key_pageup ) {
		if ( pagemax != 0 ) {
			snd 1
			page++
//			goto *label_2834
			goto *label_smith_2834
		}
	}
	if ( key == key_pagedown ) {
		if ( pagemax != 0 ) {
			snd 1
			page--
//			goto *label_2834
			goto *label_smith_2834
		}
	}
	if ( key == key_cancel ) {
		return 0
	}
//	goto *label_2835
	goto *label_smith_2835

⑨関数getencplimitの移植

ここからは関数の移植です。AF合成時のエンチャ強度限界の取得処理getencplimitを移植しましょう。特に変更する要素はなさそうです。

/* 鍛冶 AF合成用 エンチャント強度限界の取得処理 */
#defcfunc getencplimit int prm_1433
	val@m5 = prm_1433 / 10000
	if ( val@m5 != 0 ) {
		if ( val@m5 == 1 ) {
			return 50
		}
		if ( val@m5 == 2 ) {
			return 100
		}
		if ( val@m5 == 3 ) {
			return 200
		}
		if ( val@m5 == 6 ) {
			return 100
		}
		if ( val@m5 == 7 ) {
			return 100
		}
		if ( val@m5 == 8 ) {
			return 50
		}
		if ( val@m5 == 9 ) {
			return 1000
		}
	}
	if ( prm_1433 == 29 ) {
		return 100
	}
	if ( prm_1433 == 40 ) {
		return 100
	}
	return 50

⑨関数modexpsmithの移植

鍛冶ハンマーの経験値獲得処理modexpsmithを移植しましょう。txt_select以外に変更箇所はなさそうです。
……が、せっかくなのでSESTを参考にレベルと経験値を表示する処理も追加してみました。

/* 鍛冶ハンマーの経験値獲得処理 */
#deffunc modexpsmith int prm_1471, int prm_1472
	if ( inv(25, prm_1471) >= 2000 ) {
		return 0
	}
	if ( inv(26, prm_1471) < calcexpalive(inv(25, prm_1471)) ) {
		inv(26, prm_1471) += prm_1472
	}
	if ( inv(26, prm_1471) >= calcexpalive(inv(25, prm_1471)) ) {
		inv(25, prm_1471)++
		inv(26, prm_1471) = 0
		inv(27, prm_1471) = 0
		txtef 2
		snd 61
		txt_select -1, lang("あなたは鍛冶の技術の向上を感じた。", "your smithery skill increases."), "", "", "", "", "", "", "", ""
	}
	// CS追加 SESTを参考にレベルと経験値を表示
	txt_select -1, " (Lv:" + inv(25, prm_1471) + " Exp:" + fixtxt("" + double(inv(26, prm_1471) * 100) / double(calcexpalive(inv(25, prm_1471))), 6) + "%) ", "", "", "", "", "", "", "", ""
	return 1

⑩関数smithcheckの移植

長いですね……ですがもう一息なので頑張りましょう!アイテムが鍛冶に使えるか否かをチェックする処理smithcheckを移植します。3箇所あるlabel_3055をlabel_smith_3055に書き換えましょう。*label_smith_3055の移植も忘れないでください。
(とは言えこれsmithcheckの中で直接returnすれば済む話な気もしますが)

/* アイテムが鍛冶に使えるか否かのチェック処理 */
#defcfunc smithcheck int prm_1473, int prm_1474
	if ( inv(21, prm_1473) == 1 | inv(21, prm_1473) == 5 ) {
		return 1
	}
	found@m18 = 0
	repeat step
		if ( craftref(cnt * 2) == prm_1473 ) {
			found@m18 = 1
			break
		}
	loop
	if ( found@m18 ) {
		return 1
	}
	notsmith@m18 = 1
	_switch_val@m18 = prm_1474
	if ( 0 ) {
		_switch_sw@m18++
	}
	if ( _switch_val@m18 == 0 | _switch_sw@m18 ) {
		_switch_sw@m18 = 0
		reftype@m18 = refitem(inv(3, prm_1473), 5, prm_1473)
		if ( inv(3, prm_1473) == 50 ) {
			// 折れた刃(ID:50)
			notsmith@m18 = 0
		}
		else : if ( reftype@m18 >= 10000 & reftype@m18 <= 50000 ) {
			// 装備系(10000~50000)
			notsmith@m18 = 0
		}
		else : if ( inv(3, prm_1473) == 337 ) {
			// 皮(ID:337)
			notsmith@m18 = 0
		}
		else : if ( equalsitem(prm_1473, "artifacts fusion license") ) {
			// AF合成許可証
			notsmith@m18 = 0
		}
		goto *label_smith_3055
		_switch_sw@m18++
	}
	if ( _switch_val@m18 == 1 | _switch_sw@m18 ) {
		_switch_sw@m18 = 0
		reftypeminor@m18 = refitem(inv(3, prm_1473), 9, prm_1473)
		if ( reftypeminor@m18 == 77001 ) {
			// 鉱石系(77001)
			notsmith@m18 = 0
		}
		else : if ( inv(3, prm_1473) == 716 ) {
			// バニラロック(ID:716)
			notsmith@m18 = 0
		}
		else : if ( inv(3, prm_1473) == 337 ) {
			// 皮(ID:337) ドラゴン類に限る
			s@m18 = refchara(inv(23, prm_1473), 8, 1)
			if ( instr(s@m18, 0, "/dragon/") != (-1) ) {
				notsmith@m18 = 0
			}
		}
		goto *label_smith_3055
		_switch_sw@m18++
	}
	if ( _switch_val@m18 == 2 | _switch_sw@m18 ) {
		_switch_sw@m18 = 0
		reftype@m18 = refitem(inv(3, prm_1473), 5, prm_1473)
		if ( reftype@m18 >= 10000 & reftype@m18 <= 50000 ) {
			if ( inv(4, prm_1473) == 4 | inv(4, prm_1473) == 5 ) {
				if ( ibit(10, prm_1473) == 0 & ibit(18, prm_1473) == 0 ) {
					notsmith@m18 = 0
				}
			}
		}
		goto *label_smith_3055
	}

*label_smith_3055
	return notsmith@m18

⑪関数reinforcecheckの移植

最後です。会心の出来や自信作の場合の処理reinforcecheckを移植しましょう。ここは変更は不要です。

/* 鍛冶 会心の出来・自信作の場合の処理 */
#defcfunc reinforcecheck int prm_1485, int prm_1486
	if ( inv(40 + prm_1485 * 2, prm_1486) == 0 ) {
		return -1
	}
	encp@m22 = inv(41 + prm_1485 * 2, prm_1486)
	repeat 8
		mtenc_id@m22 = mtenc(cnt * 2, inv(24, prm_1486))
		if ( mtenc_id@m22 == 0 ) {
			break
		}
		if ( inv(40 + prm_1485 * 2, prm_1486) == mtenc_id@m22 ) {
			encp@m22 -= mtenc(1 + cnt * 2, inv(24, prm_1486))
			break
		}
	loop
	if ( encp@m22 <= 0 ) {
		return 0
	}
	return encp@m22

⑫コンパイル&次回予告

お疲れ様でした。移植が完了したらstart.hspをHSPエディタで開き、コンパイルを実行してください。正常に実行ファイルが生成されたら成功です。
次回は今回移植した関数を実際に呼び出してみましょう。

今回はコンパイル成功の確認までで一区切りです

この記事が気に入ったらサポートをしてみませんか?