code:
;与えられたキャラに対し、CFLAGやTALENTに重みをつけて合計を計算する。
;valueKeysはカンマ区切りのリスト形式で与え、重みは各キーに*nを付与する形で設定する。*1は省略可
;例：CALC_CHARA_SINGLE_DATA("TALENT",MASTER,"바늘다루기*2,새드")
;　->MASTERが바늘다루기を持っているなら2、새드を持っているなら1として、合計を返す。(両方持っているなら3を返す)
;各キーに2以上の値が入る場合、重み倍されて加算されるので注意。たとえば上位素質を2をセットすることで表現している場合が該当。
@CALC_CHARA_SINGLE_DATA(valueName,charaIndex,valueKeys)
#FUNCTION
#DIMS valueName
#DIM charaIndex
#DIMS valueKeys
#DIMS DYNAMIC splittedRangeList,100 ;とりあえず100
#DIM DYNAMIC answerValue = 0
#DIM DYNAMIC listMax
#DIMS DYNAMIC keyValue,2
#DIM DYNAMIC isMultipled
#DIM DYNAMIC index
listMax = SPLIT_STRING(valueKeys,",",splittedRangeList)
FOR index,0,listMax + 1
	isMultipled = SPLIT_STRING(splittedRangeList:index,"*",keyValue)
	SIF !isMultipled
		keyValue:1 = 1
	answerValue += EVALUATE(valueName + ":" + TOSTR(charaIndex) + ":" + keyValue:0 + "*" + keyValue:1)
NEXT
RETURNF answerValue

;与えられたキャラに対し、CFLAGやTALENTに重みをつけて合計を計算する。加算条件を設定可能
;valueKeysはパイプ区切りのリスト形式で与え、重みと加算条件をカンマ区切りで与える
;例：CALC_CHARA_SINGLE_DATA("TALENT",MASTER,"바늘다루기*2,RAND:3 == 0|새드,ABL:index:기교 >= 3")
;　->MASTERが바늘다루기を持っているなら1/3の確率で2、새드を持っており、기교が3以上あるなら1として、合計を返す。(最大で3を返す)
;各キーに2以上の値が入る場合、重み倍されて加算されるので注意。たとえば上位素質を2をセットすることで表現している場合が該当。
@CALC_CHARA_SINGLE_DATA_RULED(valueName,charaIndex,valueKeys)
#FUNCTION
#DIMS valueName
#DIM charaIndex
#DIMS valueKeys
#DIMS DYNAMIC splittedRangeList,100 ;とりあえず100
#DIM DYNAMIC answerValue = 0
#DIM DYNAMIC listMax
#DIMS DYNAMIC keyValue,2
#DIM DYNAMIC isMultipled
#DIM DYNAMIC index
#DIM DYNAMIC ruleTexts,2
listMax = SPLIT_STRING(valueKeys,"|",splittedRangeList)
FOR index,0,listMax + 1
	SIF !EVALUATE(GET_BETWEEN_STRING(splittedRangeList:index,",",1),charaIndex)
		CONTINUE
	isMultipled = SPLIT_STRING(GET_BETWEEN_STRING(splittedRangeList:index,",",0),"*",keyValue)
	SIF !isMultipled
		keyValue:1 = 1
	answerValue += EVALUATE(valueName + ":" + TOSTR(charaIndex) + ":" + keyValue:0 + "*" + keyValue:1)
NEXT
RETURNF answerValue

;与えられたキャラに対し、CFLAGやTALENTに重みをつけて積算し、倍率を計算する。
;valueKeysはカンマ区切りのリスト形式で与え、重みは各キーに*nを付与する形で設定する。*1は省略可
;logarithmは各値が何倍した値かを与える。10の累乗で表現する。これはEraBASICが小数に対応していないため。
;同じく小数対応のため、結果は必ずlastOrder倍した値を返す。省略時は1000。呼び元で/lastOrderして元の値に直すこと。なおlastOrderも、上と同じ理由で10の累乗でなければならない
;例：CALC_CHARA_SINGLE_DATA("TALENT",MASTER,"천연*11,기가셈*15",10)
;　->MASTERが천연を持っているなら1.1、기가셈を持っているなら1.5として、積算結果を返す。(両方持っているなら1.65だが、1000倍されて1650を返す)
@CALC_CHARA_MULTIPLE_DATA(valueName,charaIndex,valueKeys,logarithm,lastOrder = 1000)
#FUNCTION
#DIMS valueName
#DIM charaIndex
#DIMS valueKeys
#DIM logarithm
#DIMS DYNAMIC splittedRangeList,100 ;とりあえず100
#DIM DYNAMIC answerValue = 1
#DIM DYNAMIC listMax
#DIMS DYNAMIC keyValue,2
#DIM DYNAMIC isMultipled
#DIM DYNAMIC index
#DIM DYNAMIC multipleState
#DIM charaValue
#DIM lastOrder = 1000
listMax = SPLIT_STRING(valueKeys,",",splittedRangeList)
FOR index,0,listMax + 1
	isMultipled = SPLIT_STRING(splittedRangeList:index,"*",keyValue)
	SIF !isMultipled
		keyValue:1 = 1
	charaValue = EVALUATE(valueName + ":" + TOSTR(charaIndex) + ":" + keyValue:0)
	SIF charaValue == 0
		CONTINUE
	answerValue *= charaValue * TOINT(keyValue:1)
	multipleState += log10(logarithm)
	IF answerValue > 1000000000000000 ;オーバーフロー対策。どうせ下の方は端数で消えるので削っておく
		answerValue = answerValue / logarithm
		multipleState -= log10(logarithm)
	ENDIF
NEXT
IF multipleState < LOG10(lastOrder)
	answerValue *= POWER(10,LOG10(lastOrder) - multipleState)
	multipleState = LOG10(lastOrder)
ENDIF
RETURNF answerValue / POWER(10,multipleState - LOG10(lastOrder)) ;1000倍するので実際の値より-log10(1000)=-3する。

;与えられたキャラのABLやCFLAGについて、値の範囲ごとに重み付けをして結果を返す。
;第1引数が対象の変数、第2引数が引数、第3引数が引数、第4引数が範囲とその値。
;第1～第3引数は、STRFORM内で左辺に結合され、第4引数がパースされて右辺として結合される。
;第4引数は境界値とその重みをカラムで区切ったものを1セットとし、"|"で区切ったリストとなる。
;リストは左から順に適用し、値が境界値以下であれば該当の重みが適用。
;境界値に*のみを指定すると、その時点で問答無用で成立したものとみなす。
;例：CALC_CHARA_RANGED_DATA("ABL",MASTER,"기교","3,1|7,3|*,5")
;   ->MASTERの기교が3以下なら1、4～7ならば3、8以上なら5を返す。
;重みは最終的にTOINTして返すため、数字でなければエラーとなる。
;どの条件も満たさない場合、0を返す
@CALC_CHARA_RANGED_DATA(valueName,charaIndex,valueKey,rangeList)
#FUNCTION
#DIMS valueName
#DIM charaIndex
#DIMS valueKey
#DIMS rangeList

RETURNF GET_VALUE_FROM_RANGED_DATA(EVALUATE(valueName + ":" + TOSTR(charaIndex) + ":" + valueKey),rangeList)

@GET_VALUE_FROM_RANGED_DATA(value,rangeList)
#FUNCTION
#DIMS rangeList
#DIM value
#DIM listMax
#DIMS DYNAMIC splittedRangeList,100 ;とりあえず100
#DIMS keyValue,2
#DIM index
listMax = SPLIT_STRING(rangeList,"|",splittedRangeList)
FOR index,0,listMax + 1
	CALLF SPLIT_STRING(splittedRangeList:index,",",keyValue)
	IF keyValue:0 == "*"
		RETURNF TOINT(keyValue:1)
	ELSE
		IF value <= TOINT(keyValue:0)
			RETURNF TOINT(keyValue:1)
		ENDIF
	ENDIF
NEXT
RETURNF 0

;CALC_CHARA_RANGED_DATAの簡易版。valueListをカンマ区切りの単純な値リストと見なし、charaIndexの能力値に応じた位置の値を返す。
;例：CALC_CHARA_LISTARRAY_DATA("ABL",MASTER,"기교","0,3,6,8,10,15,17,19,20,25")
;   ->MASTERの기교が0なら0、1なら3、2なら6を返す。9以上の場合は25を返す。
;なお、valueListは0オリジンなので必要に応じ呼び元で直す
@CALC_CHARA_LISTARRAY_DATA(valueName,charaIndex,valueKey,valueList)
#FUNCTION
#DIMS valueName
#DIM charaIndex
#DIMS valueKey
#DIMS valueList
RETURNF GET_VALUE_FROM_LISTARRAY_DATA(EVALUATE(valueName + ":" + TOSTR(charaIndex) + ":" + valueKey),valueList)

@GET_VALUE_FROM_LISTARRAY_DATA(value,valueList)
#FUNCTION
#DIM value
#DIMS valueList
#DIMS DYNAMIC splittedValueList,100 ;とりあえず100
#DIM listMax
#DIM index
listMax = SPLIT_STRING(valueList,",",splittedValueList)
value = MAX(index,listMax)
RETURNF TOINT(splittedValueList:value)

;splitがCALL必須な命令なので、#FUNCTION内では使えない <-実は使えた。でもまあいいや
;しょうがないので손でパースする
@SPLIT_STRING(targetString,splitString,answerValue)
#FUNCTION
#DIMS targetString
#DIMS splitString
#DIMS REF answerValue
#DIM DYNAMIC index = 0
#DIM DYNAMIC nowPosition = 0
#DIM DYNAMIC nextPosition = -1
VARSET answerValue,""
WHILE 1
	nextPosition = STRFIND(targetString,splitString,nowPosition)
	if nextPosition < 0
		answerValue:index = %SUBSTRING(targetString,nowPosition)%
		break
	ELSE
		answerValue:index = %SUBSTRING(targetString,nowPosition,nextPosition - nowPosition)%
		nowPosition = nextPosition + STRLENS(splitString)
		index++
	ENDIF
WEND
RETURNF index

;簡易CSVパーサ。splitStringで区切ったときにindex番目(0オリジン)に来る文字列を返す。
;簡易なのでダブルクォートには対応していない。
;範囲外の場合、\C文字(中断文字)を返すので、保存する変数への格納厳禁。
@GET_BETWEEN_STRING(targetString,splitString,targetIndex)
#FUNCTIONS
#DIMS targetString
#DIMS splitString
#DIM targetIndex
#DIM DYNAMIC index = 0
#DIM DYNAMIC nowPosition = 0
#DIM DYNAMIC nextPosition = -1
FOR index,0,targetIndex+1
	nextPosition = STRFIND(targetString,splitString,nowPosition)
	IF index==targetIndex
		BREAK
	ELSEIF nextPosition < 0
		RETURNF GET_ETX_CHAR()
	ENDIF
	nowPosition = nextPosition + STRLENS(splitString)
NEXT
RETURNF SUBSTRING(targetString,nowPosition,(nextPosition < 0 ? STRLENS(targetString) # nextPosition) - nowPosition)

;制御コード文字(ETX)を返すラッパー関数。Emuera1824+v6.2の非互換対応
@GET_ETX_CHAR()
#FUNCTIONS
RETURNF CHAR_ETX

;GET_BETWEEN_STRINGに類似するが、indexは候補の中からランダムで選ばれる
@GET_RANDOM_PARTS_IN_STRING(targetString,splitter)
#FUNCTIONS
#DIMS targetString
#DIMS splitter
#DIM charMaxIndex
charMaxIndex = STRCOUNT(targetString,splitter)
RETURNF GET_BETWEEN_STRING(targetString,splitter,RAND:(charMaxIndex+1))

;splitterで区切ったときにseachKeyに一致する項目のindex(0オリジン)を返す。
;見つからなかったら-1を返す
@SEARCH_BETWEEN_STRING(targetString,splitter,searchKey)
#FUNCTION
#DIMS targetString
#DIMS gotValue = ""
#DIMS splitter
#DIM DYNAMIC index = 0
#DIMS searchKey
DO
	gotValue = %GET_BETWEEN_STRING(targetString,splitter,index++)%
	SIF gotValue == searchKey
		BREAK
LOOP gotValue != GET_ETX_CHAR()
RETURNF gotValue == GET_ETX_CHAR() ? -1 # index - 1

;キャラの全valueTypeを文字列として返す。MAX100以下を前提する。
@GET_CHARA_ABL_MAP(targetChara,valueType="ABL")
#FUNCTIONS
#DIM targetChara
#DIM index
#DIMS DYNAMIC answer = ""
#DIMS DYNAMIC valueType
#DIM value
FOR index,0,VARSIZE(valueType)
	value = EVALUATE(valueType + ":" + TOSTR(targetChara) + ":index",index)
	SIF value > 100
		throw %ABLNAME:index%의 値が100を超えています。
	answer '= answer + SUBSTRING(VAL_CONVERT_LIST,value,1)
NEXT
RETURNF answer

@GET_CHARA_STR_ABL_FROM_MAP(targetMap,targetValue,valueType="ABL")
#FUNCTION
#DIMS targetMap
#DIMS targetValue
#DIMS valueType
#DIM index
index = EVALUATE("GETNUM(" + valueType + "," + UNICODE(34) + targetValue + UNICODE(34) + ")")
SIF index < 0
	THROW CSVに定義のない値が指定されました。 : %targetValue%
RETURNF GET_CHARA_ABL_FROM_MAP(targetMap,index)

@GET_CHARA_ABL_FROM_MAP(targetMap,targetValue)
#FUNCTION
#DIMS targetMap
#DIM targetValue
RETURNF STRFIND(VAL_CONVERT_LIST,SUBSTRING(targetMap,targetValue,1))

@GET_CHARA_FIRSTCHECK(targetChara,rule:0,value:0,rule:1 = "",value:1 = 0,rule:2 = "",value:2 = 0,rule:3 = "",value:3 = 0,rule:4 = "",value:4 = 0,rule:5 = "",value:5 = 0,rule:6 = "",value:6 = 0,rule:7 = "",value:7 = 0,rule:8 = "",value:8 = 0,rule:9 = "",value:9 = 0)
#FUNCTION
#DIM targetChara
#DIMS rule,10
#DIM value,10
#DIM index
#DIM answer
FOR index,0,10
	IF EVALUATE(rule:index,targetChara)
		answer = value:index
		BREAK
	ENDIF
NEXT
RETURNF answer

;targetNoが与えられたruleを満たす場合に1を返す。
;targetNoはキャラ登録されていない可能性があり、その場合は必ず0を返す
@IS_NONEXISTABLE_CSV_CHARA_NO_RULED(targetNo,rule)
#FUNCTION
#DIM targetNo
#DIM charaIndex
#DIMS rule
charaIndex = GETCHARA(targetNo)
SIF charaIndex == -1
	RETURNF 0
RETURNF EVALUATE(rule,charaIndex)

;targetNameを持つキャラが与えられたruleを満たす場合に1を返す。
;引数以外はIS_NONEXISTABLE_CSV_CHARA_RULEDに同じ
@IS_NONEXISTABLE_CSV_CHARA_NAME_RULED(targetName,rule)
#FUNCTION
#DIMS targetName
#DIM charaIndex
#DIMS rule
charaIndex = FINDCHARA(NAME,targetName)
IF charaIndex == -1
	charaIndex = FINDCHARA(CALLNAME,targetName)
	SIF charaIndex == -1
		RETURNF 0
ENDIF
RETURNF EVALUATE(rule,charaIndex)

;与えられた名前をキャラ名とみなし、NAMEまたはCALLNAMEが一致するキャラのNoを返す
@GET_CHARA_NO_FROM_NAME(charaName)
#FUNCTION
#DIMS charaName
#DIM answerList,1
#DIM ret
ret = GET_CHARA_NO_LIST_FROM_NAME(charaName,answerList)
RETURNF answerList:0

;charaListで与えられた文字列をキャラ名のリストとみなして1キャラ分ずつ取り出し、NAMEまたはCALLNAMEが一致するキャラのNoをリストで返す
@GET_CHARA_NO_LIST_FROM_NAME(charaList,answerList)
#FUNCTION
#DIMS charaList
#DIM REF answerList
#DIM charaNoIndex
#DIM DYNAMIC charaListIndex = 0
#DIMS targetCharaName
#DIM ret
ret = INIT_LIST(answerList)
SIF charaList == ""
	RETURNF 0
WHILE 1
	targetCharaName = %GET_BETWEEN_STRING(charaList,",",charaListIndex)%
	SIF targetCharaName == GET_ETX_CHAR()
		RETURNF GET_LIST_LAST_ELEMENT(answerList) + 1
	FOR charaNoIndex,1,100000
		SIF !EXISTCSV(charaNoIndex)
			CONTINUE
		IF CSVNAME(charaNoIndex) == targetCharaName || CSVCALLNAME(charaNoIndex) == targetCharaName
			ret = LIST_ADD(answerList,charaNoIndex)
			BREAK
		ENDIF
	NEXT
	charaListIndex++
WEND
RETURNF 1


code:
;-------------------------------------------------
;@COMPATITION  能力値対抗判定
;キャラクターARGとARG:3のARG:1で示される能力値による対抗判定。　ARG:2はMASTERの能力に加算される修正
;能力値が対等で勝率50％。　1差ごとに5％ 乱数96以上で自動失敗　5以下で自動成功
;返り値　0で成功　1で失敗
;-------------------------------------------------
@COMPATITION, ARG, ARG:1, ARG:2, ARG:3
#DIM LOCAL2
LOCAL = ARG:3
;成功率の算出
IF ARG:1 == 100
;運動と戦闘の複合判定
	LOCAL:1 = ABL:LOCAL:23 + ABL:LOCAL:24 + ARG:2
	SIF TALENT:LOCAL:작은체형 == 1
		LOCAL:1 -= 2
	LOCAL:1 -= ABL:ARG:23
	LOCAL:1 -= ABL:ARG:24
	SIF TALENT:ARG:작은체형 == 1
		LOCAL:1 += 2
ELSE
	LOCAL2 = ARG:1
	LOCAL:1 = ABL:LOCAL:LOCAL2 - ABL:ARG:LOCAL2 + ARG:2
	IF LOCAL2 == 23 ||  LOCAL2 == 24
		SIF TALENT:LOCAL:작은체형 == 1
			LOCAL:1 -= 1
		SIF TALENT:ARG:작은체형 == 1
			LOCAL:1 += 1
	ENDIF
ENDIF
LOCAL:1 *= 5
LOCAL:1 += 50
;乱数
LOCAL = RAND:1000
LOCAL /= 10
LOCAL += 1
IF LOCAL:1 >= LOCAL && LOCAL <= 95
	RETURN 0
ELSEIF LOCAL <= 5
	RETURN 0
ELSE
	RETURN 1
ENDIF

repo_name: Catalyst/B

license: unknown


code:
;このファイルは制御コードを扱っているため、テキストエディタでの編集不可
;バイナリエディタを使用すること

;nullを読ますと思いっきり解析失敗するので作らない。作れない
;CRやLFも解析に失敗するので無理。別にラッパー関数を作る
#DIMS CONST CHAR_SOH = ""

#DIMS CONST CHAR_STX = ""

#DIMS CONST CHAR_ETX = ""

#DIMS CONST CHAR_EOT = ""

#DIMS CONST CHAR_ENQ = ""

#DIMS CONST CHAR_ACK = ""

#DIMS CONST CHAR_BEL = ""

#DIMS CONST CHAR_BS = ""

#DIMS CONST CHAR_HT = "	"

#DIMS CONST CHAR_VT = ""

#DIMS CONST CHAR_FF = ""

#DIMS CONST CHAR_SO = ""

#DIMS CONST CHAR_SI = ""

#DIMS CONST CHAR_DLE = ""

#DIMS CONST CHAR_DC1 = ""

#DIMS CONST CHAR_DC2 = ""

#DIMS CONST CHAR_DC3 = ""

#DIMS CONST CHAR_DC4 = ""

#DIMS CONST CHAR_NAK = ""

#DIMS CONST CHAR_SYN = ""

#DIMS CONST CHAR_ETB = ""

#DIMS CONST CHAR_CAN = ""

#DIMS CONST CHAR_EM = ""

#DIMS CONST CHAR_SUB = ""

#DIMS CONST CHAR_ESC = ""

#DIMS CONST CHAR_FS = ""

#DIMS CONST CHAR_GS = ""

#DIMS CONST CHAR_RS = ""

#DIMS CONST CHAR_US = ""

#DIMS CONST CHAR_DEL = ""


code:
@VAGINA_DESC(charaIndex = -1,isOmitOverWear = 0)
#FUNCTIONS
#DIM charaIndex
#DIMS answer
#DIM position
#DIM isOmitOverWear
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TRANSPOSE_LEVEL(charaIndex)
	CASE 3
		answer = \@  !isOmitOverWear ? %GET_CHARA_WEAR_NAME(6,charaIndex)%에 숨겨진 # \@하반신
	CASE 2
		answer = \@ IS_WEARING(6,charaIndex) && !isOmitOverWear ? %GET_CHARA_WEAR_NAME(6)% 너머로  # \@%GET_CHARA_WEAR_NAME(4,charaIndex)%에 숨겨진 하반신
	CASE 1
		IF (IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)) && !isOmitOverWear
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(4,index)",4,"IS_WEARING(6,index)",6)
			answer = %GET_CHARA_WEAR_NAME(position,charaIndex)% 너머로
		ELSE
			answer =
		ENDIF
		SIF TEQUIP:49
			answer += "밧줄 속옷이 희미하게 떠올라、"
		;윤활LV4以上
		IF charaIndex == TARGET && PALAM:욕정 >= PALAMLV:5 && TALENT:charaIndex:남자
			answer += "발기된 음경을 뚜렷이 알 수 있다"
		ELSEIF charaIndex == TARGET && PALAM:charaIndex:윤활 >= PALAMLV:5
			answer += "애액으로 비소가 비친다"
		ENDIF
		answer += GET_CHARA_WEAR_NAME(2,charaIndex)
	CASE 0
		IF (IS_WEARING(2,charaIndex) || IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)) && !isOmitOverWear
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(2,index)",2,"IS_WEARING(4,index)",4,"IS_WEARING(6,index)",6)
			answer = %GET_CHARA_WEAR_NAME(position,charaIndex)% 너머로
		ELSE
			answer =
		ENDIF
		SIF TEQUIP:49
			answer += "밧줄 속옷을 자극당해"
		;윤활LV4以上
		IF charaIndex == TARGET && TALENT:charaIndex:남자 && PALAM:charaIndex:욕정 >= PALAMLV:4
			answer += "단단하게 발기한"
		ELSEIF charaIndex == TARGET && PALAM:charaIndex:윤활 >= PALAMLV:4
			answer += "흠뻑 젖은"
		ELSEIF charaIndex == TARGET && PALAM:charaIndex:욕정 >= PALAMLV:4
			answer += "흥분해서 분홍색으로 물든"
		ENDIF
		answer += " 노출된 "
		IF TALENT:charaIndex:남자
			answer += "페니스"
		ELSEIF TALENT:charaIndex:초등학생 || TALENT:charaIndex:작은체형
			answer += "어린 균열"
		ELSE
			answer += "비렬"
		ENDIF
	CASEELSE
		THROW 투과 레벨이 부정합니다。 : {GET_BOTTOM_TRANSPOSE_LEVEL(charaIndex)}
ENDSELECT
RETURNF answer

@ANAL_DESC(charaIndex = -1, isOmitOverWear = 0)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
#DIM isOmitOverWear
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TRANSPOSE_LEVEL(charaIndex)
	CASE 3
		answer = \@ !isOmitOverWear ? %GET_CHARA_WEAR_NAME(6,charaIndex)%에 숨겨진  # \@하반신
	CASE 2
		answer = \@ IS_WEARING(6,charaIndex) && !isOmitOverWear ? %GET_CHARA_WEAR_NAME(6)%너머로  # \@%GET_CHARA_WEAR_NAME(4,charaIndex)%에 숨겨진 하반신
	CASE 1
		IF (IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)) && !isOmitOverWear
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(4,index)",4,"IS_WEARING(6,index)",6)
			answer = %GET_CHARA_WEAR_NAME(position,charaIndex)% 너머로
		ELSE
			answer =
		ENDIF
		SIF TEQUIP:49
			answer += "밧줄 속옷이 희미하게 떠올라 "
		answer += GET_CHARA_WEAR_NAME(2,charaIndex)
	CASE 0
		IF (IS_WEARING(2,charaIndex) || IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)) && !isOmitOverWear
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(2,index)",2,"IS_WEARING(4,index)",4,"IS_WEARING(6,index)",6)
			answer = %GET_CHARA_WEAR_NAME(position,charaIndex)% 너머로 보인다
		ELSE
			answer =
		ENDIF
		SIF TEQUIP:49
			answer += "밧줄 속옷이 죄어들어 벌려져 있는 "
		SELECTCASE EXP:charaIndex:Ａ경험
			CASE IS <= 10
				answer += "굳게 닫힌 채의 "
			CASE IS <= 50
				answer += "예쁜 핑크색 그대로의 "
			CASE IS <= 100
				answer += "완전히 느슨해진 "
			CASE IS <= 500
				answer += "마치 성기처럼 부풀어오른 "
			CASE IS <= 1000
				answer += "깊은 곳까지 보일 듯이 느슨해진 "
			CASEELSE
				answer += "완전히 성기로 개발되어 버린 "
		ENDSELECT
		answer += \@ RAND:2 == 0 ? "애널" # "국혈" \@
	CASEELSE
		THROW 투과 레벨이 부정합니다。 : {GET_BOTTOM_TRANSPOSE_LEVEL(charaIndex)}
ENDSELECT
RETURNF answer

@CHEST_DESC(charaIndex = -1, isOmitOverWear = 0)
#FUNCTIONS
#DIM charaIndex
#DIMS answer
#DIM isOmitOverWear
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_TOP_TRANSPOSE_LEVEL(charaIndex)
	CASE 3
		answer = \@ !isOmitOverWear ? %GET_CHARA_WEAR_NAME(6,charaIndex)%에 숨겨진  # \@가슴
	CASE 2
		answer = \@ IS_WEARING(6,charaIndex) && !isOmitOverWear ? %GET_CHARA_WEAR_NAME(6,charaIndex)%너머로  # \@%GET_CHARA_WEAR_NAME(5,charaIndex)%
		IF TALENT:charaIndex:남자
			answer += "에 싸인 가슴"
		ELSEIF TALENT:charaIndex:폭유 || TALENT:charaIndex:거유
			answer += "의 위에서도 뚜렷한 존재감을 주장하는 가슴"
		ELSEIF TALENT:charaIndex:빈유 || TALENT:charaIndex:절벽
			answer += "의 위에서는 알기 힘든 가슴"
		ELSE
			answer += "에 싸인 다소곳한 가슴"
		ENDIF
	CASE 1
		SELECTCASE 1
			CASE IS_WEARING(5,charaIndex) && !isOmitOverWear
				answer = %GET_CHARA_WEAR_NAME(5,charaIndex)% 너머로
			CASE IS_WEARING(6,charaIndex) && !isOmitOverWear
				answer = %GET_CHARA_WEAR_NAME(6,charaIndex)% 너머로
			CASEELSE
				answer =
		ENDSELECT
		SIF TEQUIP:49
			answer += "밧줄 속옷이 어렴풋이 떠올라、"
		IF TALENT:charaIndex:남자
			answer += GET_CHARA_WEAR_NAME(3,charaIndex) + " 너머의 가슴"
		ELSEIF TALENT:charaIndex:폭유 || TALENT:charaIndex:거유
			answer += GET_CHARA_WEAR_NAME(3,charaIndex) + "에서 쏟아질 것 같은 가슴"
		ELSEIF TALENT:charaIndex:빈유 || TALENT:charaIndex:절벽
			answer += GET_CHARA_WEAR_NAME(3,charaIndex) + "는 필요없을 것 같은 가슴"
			;ひでぇ
		ELSE
			answer += GET_CHARA_WEAR_NAME(3,charaIndex) + "에 싸인 다소곳한 가슴"
		ENDIF
	CASE 0
		SELECTCASE 1
			CASE IS_WEARING(3,charaIndex) && !isOmitOverWear
				answer = %GET_CHARA_WEAR_NAME(3,charaIndex)% 너머로
			CASE IS_WEARING(5,charaIndex) && !isOmitOverWear
				answer = %GET_CHARA_WEAR_NAME(5,charaIndex)% 너머로
			CASE IS_WEARING(6,charaIndex) && !isOmitOverWear
				answer = %GET_CHARA_WEAR_NAME(6,charaIndex)% 너머로
			CASEELSE
				answer =
		ENDSELECT
		SIF TEQUIP:49
			answer += "밧줄 속옷에 쥐여짜여、"
		;윤활LV4以上
		IF charaIndex == TARGET && TFLAG:53
			answer += "흥분한 나머지 젖꼭지를 쫑긋쫑긋 발기시킨"
		ELSEIF charaIndex == TARGET && PALAM:욕정 >= PALAMLV:4
			answer += "흥분해서 분홍색으로 물든"
		ENDIF
		answer += " 노출된 "
		IF TALENT:charaIndex:남자
			answer += "가슴"
		ELSEIF TALENT:charaIndex:폭유 || TALENT:charaIndex:거유
			answer += "파르르 떨리는 가슴"
		ELSEIF TALENT:charaIndex:빈유 || TALENT:charaIndex:절벽
			answer += "얇은 가슴"
			;直球ｗ
		ELSE
			answer += "다소곳한 가슴"
		ENDIF
	CASEELSE
		THROW 투과 레벨이 부정합니다。 : {GET_BOTTOM_TRANSPOSE_LEVEL(charaIndex)}
ENDSELECT
RETURNF answer

;가슴を노출させるテキストの設定。ずらせるか、まくれるか、穴が開いているかなどを考慮し、できるだけ進む。
;ただし、接触描写に進む前提なので、可視性は考慮しない
@DESCRIPTION_TEXT_CHESTOPEN(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_TOP_TOUCH_LEVEL(charaIndex)
	CASE 3
		answer = %GET_CHARA_WEAR_NAME(6,charaIndex)% 너머로
	CASE 2
		IF IS_WEARING(6,charaIndex)
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(6,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%에 뚫린 구멍으로 나온
				CASE IS_CHARA_CLOTH_FRONTOPEN(6,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%의 앞을 풀어헤쳐、
				CASE GET_CHARA_CLOTH_HOLED(6,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%を 제껴서 튀어나온
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer =
		ENDIF
		answer += GET_CHARA_WEAR_NAME(5,charaIndex) + "너머로 "
	CASE 1
		IF IS_WEARING(5,charaIndex) || IS_WEARING(6,charaIndex)
			position = IS_WEARING(6,charaIndex) ? 6 # 5
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%에 뚫린 구멍으로 엿보이는
				CASE IS_CHARA_CLOTH_FRONTOPEN(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 앞을 풀어헤쳐、
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 제껴서 튀어나온、
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer =
		ENDIF
		answer += GET_CHARA_WEAR_NAME(3,charaIndex) + "너머로 "
	CASE 0
		IF IS_WEARING(3,charaIndex) || IS_WEARING(5,charaIndex) || IS_WEARING(6,charaIndex)
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(6,index)",6,"IS_WEARING(5,index)",5,"IS_WEARING(3,index)",3)
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 구멍으로 보이는
				CASE IS_CHARA_CLOTH_FRONTOPEN(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 앞을 풀어헤쳐、드러난
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%을 제껴서、흘러내린
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer = 노출된
		ENDIF
	CASEELSE
		THROW 부정한 pattern입니다。
ENDSELECT
RETURNF answer

@DESCRIPTION_TEXT_CHEST_TOUCH(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_TOP_TOUCH_LEVEL(charaIndex)
	CASE 3
		answer =
	CASE 2
		answer = %GET_CHARA_WEAR_NAME(5,charaIndex)%
		IF TALENT:charaIndex:남자
			answer = %answer%에 싸인
		ELSEIF TALENT:charaIndex:폭유 || TALENT:charaIndex:거유
			answer = %answer%의 의 위에서도 뚜렷한 존재감을 주장하는
		ELSEIF TALENT:charaIndex:빈유 || TALENT:charaIndex:절벽
			answer = %answer%의 의 위에서는 알기 힘든
		ELSE
			answer = %answer%에 싸인 다소곳한
		ENDIF
	CASE 1
		answer = %GET_CHARA_WEAR_NAME(3,charaIndex)%
		IF TALENT:charaIndex:남자
			answer = %answer%에 싸인
		ELSEIF TALENT:charaIndex:폭유 || TALENT:charaIndex:거유
			answer = %answer%의 위에서도 분명히 알 수 있는
		ELSEIF TALENT:charaIndex:빈유 || TALENT:charaIndex:절벽
			answer = %answer%의 의 위에서는 알기 힘든
		ELSE
			answer = %answer%에 싸인 다소곳한
		ENDIF
	CASE 0
		IF TALENT:charaIndex:남자
			answer =
		ELSEIF TALENT:charaIndex:폭유 || TALENT:charaIndex:거유
			answer = 양손으로 수습되지 않을 만큼 커다란
		ELSEIF TALENT:charaIndex:빈유 || TALENT:charaIndex:절벽
			answer = 겨우 부풀어 오르는 기미를 보이는
		ELSE
			answer = 다소곳한
		ENDIF
ENDSELECT
RETURNF answer

@DESCRIPTION_TEXT_NIPPLE_TOUCH(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
answer = %DESCRIPTION_TEXT_CHEST_TOUCH(charaIndex)%가슴の上の
SELECTCASE GET_TOP_TOUCH_LEVEL(charaIndex)
	CASE 3,2,1
		position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(6,index)",6,"IS_WEARING(5,index)",5,"IS_WEARING(3,index)",3)
		SELECTCASE 1
			CASE TALENT:charaIndex:299 && PALAM:charaIndex:6 >= PALAMLV:3
				answer = %answer% 완전히 단단해져서 %GET_WEAR_NAME(position,charaIndex)%에 모유를 적신
			CASE TALENT:charaIndex:299
				answer = %answer%%GET_WEAR_NAME(position,charaIndex)%에 모유를 적신
			CASE PALAM:charaIndex:6 >= PALAMLV:3
				answer = %answer% 완전히 단단해진
		ENDSELECT
	CASE 0
		SELECTCASE 1
			CASE TALENT:charaIndex:299 && PALAM:charaIndex:6 >= PALAMLV:3
				answer = %answer% 완전히 단단해져서 모유를 내뿜는
			CASE TALENT:charaIndex:299
				answer = %answer% 모유가 떨어지는
			CASE PALAM:charaIndex:6 >= PALAMLV:3
				answer = %answer% 완전히 단단해진
		ENDSELECT
ENDSELECT
answer = %answer% 유두
RETURNF answer

;비소・クリを노출させるテキストの設定。ずらせるか、まくれるか、穴が開いているかなどを考慮し、できるだけ進む。
;ただし、接触描写に進む前提なので、可視性は考慮しない。またクリと両方あるので、具体的な場所は描写しない(別関数を用意)ので、呼び元で使い分ける。
@DESCRIPTION_TEXT_VAGINAOPEN(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TOUCH_LEVEL(charaIndex)
	CASE 3
		answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%너머로
	CASE 2
		IF IS_WEARING(6,charaIndex)
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(6,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%에 뚫린 구멍에 손을 넣어서
				CASE IS_CHARA_CLOTH_FRONTOPEN(6,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%의 앞을 벌려
				CASE IS_CHARA_CLOTH_SKIRT(6,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%を 걷어올려
				CASE GET_CHARA_CLOTH_HOLED(6,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%を 제껴서 튀어나온
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer =
		ENDIF
		answer += GET_CHARA_WEAR_NAME(4,charaIndex) + "너머로 "
	CASE 1
		IF IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)
			position = IS_WEARING(4,charaIndex) ? 4 # 6
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%에 뚫린 구멍으로 엿보이는
				CASE IS_CHARA_CLOTH_FRONTOPEN(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 앞을 벌려
				CASE position == 4 && IS_CHARA_CLOTH_SKIRT(position,charaIndex) && ABL:charaIndex:노출증 >= 3
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올리게하고
				CASE IS_WEARING(position,charaIndex) && IS_CHARA_CLOTH_SKIRT(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 제끼고 보이게 한
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer =
		ENDIF
		answer += GET_CHARA_WEAR_NAME(2,charaIndex) + "너머로 "
	CASE 0
		IF IS_WEARING(2,charaIndex) || IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(6,index)",6,"IS_WEARING(4,index)",4,"IS_WEARING(2,index)",2)
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 구멍으로 엿보이는
				CASE IS_CHARA_CLOTH_FRONTOPEN(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 앞을 벌려
				CASE position == 4 && IS_CHARA_CLOTH_SKIRT(position,charaIndex) && ABL:charaIndex:노출증 >= 3
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올리게하고
				CASE IS_CHARA_CLOTH_SKIRT(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 제끼고 노출된
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer = 아무것도 감추지 않은
		ENDIF
	CASEELSE
		THROW 부정한 pattern입니다。
ENDSELECT
RETURNF answer

@DESCRIPTION_TEXT_VAGINA_TOUCH(charaIndex = -1,isPenisDesc = 0)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
#DIM isPenisDesc
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TOUCH_LEVEL(charaIndex)
	CASE 3
		answer = 하반신
	CASE 2
		IF charaIndex == TARGET
			IF TALENT:charaIndex:남자 || (TALENT:charaIndex:후타나리 && isPenisDesc)
				answer = \@ PALAM:욕정 >= PALAMLV:5 ? 옷 위에서도 알아볼 수 있을 만큼 우뚝 솟아오른 # 시들어있는 \@ 페니스
			ELSE
				answer = \@ PALAM:윤활 >= PALAMLV:5 ? 애액으로 색이 변하고 있는 # \@하반신
			ENDIF
		ELSE
			IF TALENT:charaIndex:남자 || (TALENT:charaIndex:후타나리 && isPenisDesc)
				answer =  페니스의 부풂
			ELSE
				answer = 비소
			ENDIF
		ENDIF
	CASE 1
		IF charaIndex == TARGET
			IF TALENT:charaIndex:남자 || (TALENT:charaIndex:후타나리 && isPenisDesc)
				answer = %GET_CHARA_WEAR_NAME(2,charaIndex)%의 위에서\@ PALAM:욕정 >= PALAMLV:5 ? 도 분명히 알 수 있을만큼 발기한 # 는 부풀어있는 것만 알 수 있는 \@ 페니스
			ELSE
				answer = \@ PALAM:윤활 >= PALAMLV:5 ? 애액으로 비쳐보이는 # \@ 비소
			ENDIF
		ELSE
			IF TALENT:charaIndex:남자 || (TALENT:charaIndex:후타나리 && isPenisDesc)
				answer =  페니스의 부풂
			ELSE
				answer = 비소 ;クレヴァス
			ENDIF
		ENDIF
	CASE 0
		IF charaIndex == TARGET
			IF TALENT:charaIndex:남자 || (TALENT:charaIndex:후타나리 && isPenisDesc)
				answer = \@ PALAM:욕정 >= PALAMLV:5 ? 딱딱하게 우뚝 선 # 시들어있는 \@ 페니스
			ELSE
				SELECTCASE 1
					CASE EXP:출산경험 >= 1 && PALAM:윤활 >= PALAMLV:5
						answer = 아이를 낳아서 칠칠치 못하게 열리게 된、점액을 흘리는
					CASE EXP:출산경험 >= 1
						answer = 아이를 낳아서 칠칠치 못하게 열리게 된、
					CASE EXP:Ｖ확장경험 >= 10 && PALAM:윤활 >= PALAMLV:5
						answer = 확장되어 빠끔히 열리게 된、 점액을 흘리는
					CASE EXP:Ｖ확장경험 >= 10 && RAND:2 == 0
						answer = 확장되어 빠끔히 열린
					CASE EXP:Ｖ경험 == 0 && PALAM:윤활 >= PALAMLV:3
						answer = 아직 남자를 모른다고는 믿기지 않을 만큼\@ PALAM:윤활 >= PALAMLV:5 ?  흠뻑 # \@ 젖은
					CASE EXP:Ｖ경험 == 0 && RAND:2 == 0
						answer = 아직 남자를 모르고 순결한
					CASE EXP:Ｖ경험 < 50 && RAND:2 == 0
						answer = 아직 거의 사용되지 않고 순결한
					CASE EXP:Ｖ경험 >= 500 && RAND:2 == 0
						answer = 능숙해진
					CASE PALAM:윤활 >= PALAMLV:5
						answer = 애액으로 질척해진
					CASE PALAM:윤활 == 0
						answer = 메마른
					CASE PALAM:욕정 >= PALAMLV:5
						answer = 흥분해서 분홍색으로 물든
					CASEELSE
						answer =
				ENDSELECT
				answer += " 비소"
			ENDIF
		ELSE
			IF TALENT:charaIndex:남자 || (TALENT:charaIndex:후타나리 && isPenisDesc)
				answer = 훤히 보이는 페니스
			ELSE
				answer = 훤히 보이는 비소
			ENDIF
		ENDIF
	CASEELSE
		THROW 부정한 pattern입니다。
ENDSELECT
RETURNF answer

@DESCRIPTION_TEXT_ANAL_TOUCH(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TOUCH_LEVEL(charaIndex)
	CASE 3
		answer = 하반신
	CASE 2,1
		answer = 엉덩이 뒤 오므라든 곳
	CASE 0
		SELECTCASE 1
			CASE PALAM:charaIndex:윤활 >= PALAMLV:5
				answer = 미끈거리며 요염하게 빛나는
			CASE PALAM:charaIndex:욕정 >= PALAMLV:5
				answer = 흥분하여 꿈틀꿈틀 움직이는
			CASE EXP:charaIndex:Ａ경험 >= 500
				answer = 성기처럼 부드럽게 부풀어오른
			CASE EXP:charaIndex:Ａ경험 < 50
				answer = 아직 예쁜 핑크색의
			CASE EXP:charaIndex:Ａ경험 < 10
				ANSWER = 굳게 닫힌
			CASEELSE
				answer =
		ENDSELECT
		answer += \@ RAND:3 == 0 ?  애널 #  국혈 \@ ;アヌス
ENDSELECT
RETURNF answer

@DESCRIPTION_TEXT_CRI_TOUCH(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TOUCH_LEVEL(charaIndex)
	CASE 3,2,1 ;服越しの間は兼用
		answer = %DESCRIPTION_TEXT_VAGINA_TOUCH(charaIndex)%
	CASE 0
		IF charaIndex == TARGET
			IF TALENT:charaIndex:남자 || TALENT:charaIndex:후타나리
				answer = %DESCRIPTION_TEXT_VAGINA_TOUCH(charaIndex,1)%
			ELSE
				SELECTCASE 1
					CASE PALAM:윤활 >= PALAMLV:5
						answer = 애액으로 요염하게 빛나는
					CASE PALAM:욕정 >= PALAMLV:5
						answer = 애처로울 정도로 발기한
					CASEELSE
						answer =
				ENDSELECT
				answer += " 클리토리스"
			ENDIF
		ELSE
			IF TALENT:charaIndex:남자 || TALENT:charaIndex:후타나리
				answer = %DESCRIPTION_TEXT_VAGINA_TOUCH(charaIndex,1)%
			ELSE
				answer = 훤히 보이는 클리토리스
			ENDIF
		ENDIF
	CASEELSE
		THROW 부정한 pattern입니다。
ENDSELECT
RETURNF answer

;애널を노출させるテキストの設定。ずらせるか、まくれるか、穴が開いているかなどを考慮し、できるだけ進む。
;ただし、接触描写に進む前提なので、可視性は考慮しない。ほぼ비소と同じだが、前開きは無視する
@DESCRIPTION_TEXT_ANALOPEN(charaIndex = -1)
#FUNCTIONS
#DIM charaIndex
#DIM position
#DIMS answer
SIF charaIndex == -1
	charaIndex = TARGET
SELECTCASE GET_BOTTOM_TOUCH_LEVEL(charaIndex)
	CASE 3
		answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%너머로
	CASE 2
		IF IS_WEARING(6,charaIndex)
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(6,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%에 뚫린 구멍에 손을 넣어서
				CASE IS_CHARA_CLOTH_SKIRT(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE GET_CHARA_CLOTH_HOLED(6,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(6,charaIndex)%を 제껴서 튀어나온
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer =
		ENDIF
		answer += GET_CHARA_WEAR_NAME(4,charaIndex) + "너머로 "
	CASE 1
		IF IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)
			position = IS_WEARING(4,charaIndex) ? 4 # 6
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%에 뚫린 구멍으로 엿보이는
				CASE position == 4 && IS_CHARA_CLOTH_SKIRT(position,charaIndex) && ABL:charaIndex:노출증 >= 3
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE IS_CHARA_CLOTH_SKIRT(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 제끼고 보이게 한
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer =
		ENDIF
		answer += GET_CHARA_WEAR_NAME(2,charaIndex) + "너머로 "
	CASE 0
		IF IS_WEARING(2,charaIndex) || IS_WEARING(4,charaIndex) || IS_WEARING(6,charaIndex)
			position = GET_CHARA_FIRSTCHECK(charaIndex,"IS_WEARING(2,index)",2,"IS_WEARING(4,index)",4,"IS_WEARING(6,index)",6)
			SELECTCASE 1
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 2
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%의 구멍으로 훤히 보이는
				CASE position == 4 && IS_CHARA_CLOTH_SKIRT(position,charaIndex) && ABL:charaIndex:노출증 >= 3
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE IS_CHARA_CLOTH_SKIRT(position,charaIndex)
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 걷어올려
				CASE GET_CHARA_CLOTH_HOLED(position,charaIndex) == 1
					answer = %GET_CHARA_WEAR_NAME(position,charaIndex)%を 제끼고 노출된
				CASEELSE
					THROW 부정한 pattern입니다。
			ENDSELECT
		ELSE
			answer = 아무것도 덮을 것이 없는
		ENDIF
	CASEELSE
		THROW 부정한 pattern입니다。
ENDSELECT
RETURNF answer


code:
;------------------------------------------------------------------------------
;	DISPLAY_COMMON_FUNCTION.ERB　ページつき表示共通関数 v0.01
;
;	導入対象バリアント：	era_inSchoolA ver0.08
;	バリアント製作者：	inSchool ◆ALP/BZZ2kc 様
;	文責：			不眠症の旅人（271）
;				タブ幅推奨：8　改行文字数推奨：80
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
;현재、プリセットを組み込み中
;将来的には、引数である程度自由の利いた表示ができるようにしたい
;------------------------------------------------------------------------------
;ARG=DISPLAY_CONDITIONの第1引数参照　ARG:1～ARG:6：未使用？　filterFunc:対象絞り込み用の追加条件(文字列),displayFunc:各行の表示内容を上書きする
@DISPLAY_COMMON , ARG , ARG:1 , ARG:2 , ARG:3 , ARG:4 , ARG:5 , ARG:6 , filterFunc="" , displayFunc=""

;----------使用変数初期処理部

;プリセット変数をゼロパディングして文字列化 TRYCALLFORM用
#DIMS setNumStr
#DIMS filterFunc
#DIMS displayFunc
#DIM CONST viewCount = 20
setNumStr = {ARG}
SIF ARG < 10
	setNumStr = 0{ARG}

P:52 = 0
P:54 = 0
P:55 = ARG

;----------能力／プロファイル閲覧時のページ履歴読み込みギミック
IF ARG == 2 || ARG == 8
	P:53 = P:56
ELSEIF ARG == 16 && (P == 12 || P == 14)
	P:53 = P:56
ELSE
	P:53 = 0
	P:56 = 0
ENDIF

;----------キャラクター抽出部
$LOOP_DISPLAY

				;ページ分割処理時のループ箇所
DRAWLINE

;----------ヘッダ描画

TRYCALLFORM DISPLAY_SET%setNumStr%_INDEX
FLAG:34 = 0

;----------キャラクタ描画

REPEAT CHARANUM

	;CONTINUE／GOTO文の処理用変数初期化
	L:21 = 0
	CFLAG:COUNT:199 = 0

;----------フィルタリング判定
;フィルタリングがONのキャラは除外
	SIF CFLAG:COUNT:200 == 1
		CONTINUE

;----------ここより関数処理（条件分岐）
	TRYCCALLFORM DISPLAY_SET%setNumStr%_FUNCTION
	CATCH
		CALL ALL_CHARA_FUNCTION
	ENDCATCH

	SIF L:21 == 1
		CONTINUE
;----------ここまで

;----------ここより条件判定処理

	TRYCCALLFORM DISPLAY_SET%setNumStr%_JUDGMENT
	CATCH
		CALL ALL_CHARA_JUDGMENT
	ENDCATCH

	IF filterFunc != ""
		SIF COUNT < 0 || CHARANUM < COUNT
			CONTINUE
		SIF !EVALUATE(filterFunc,COUNT)
			CONTINUE
	ENDIF

;----------ここまで

;----------ページ分割用カウント／分岐処理
	P:52 += 1

	;現在のページ範囲内のキャラクタなら表示開始
	IF P:52 > P:53 && P:52 <= P:53 + viewCount

;----------対象者色分け設定
		IF (FLAG:93 % viewCount) == 1 && ARG == 1
			IF ALLOW_CONTACT_CORE(COUNT) != 0
				IF IS_DAYTIME() && IS_DAYTIME_TRAIN_ALLOWED(MASTER)
					SIF !IS_DAYTIME_TRAIN_ALLOWED(COUNT)
						SETCOLOR 128,128,255
				ELSE
					SETCOLOR 199 ,199 ,199
				ENDIF
			ELSE
				SETCOLOR 127 ,127 ,127
			ENDIF
		ENDIF
		IF (FLAG:93 % viewCount) == 1 && ARG == 8
			;R:1 = R
			;G:1 = G
			;B:1 = B
			;R = CFLAG:COUNT:195
			;G = CFLAG:COUNT:196
			;B = CFLAG:COUNT:197
			;IF R == 0 && G == 0 && B == 0
			;	RESETCOLOR
			;ELSE
			;	SETCOLOR R, G, B
			;ENDIF
			;R = R:1
			;G = G:1
			;B = B:1
			CALL SET_CHARACOLOR(COUNT)
		ENDIF
		IF (FLAG:93 % viewCount) == 1 && ARG == 16
			SIF P == 12 && COUNT == C:21
				SETCOLOR 0 ,239 ,239
			SIF P == 14 && COUNT == C:21
				SETCOLOR 0 ,239 ,239
			SIF (P == 12 || P == 14) && COUNT != C:21
				RESETCOLOR
		ENDIF
		IF ARG == 7
			SIF CFLAG:COUNT:1000 == 4
				SETCOLOR 0,255,0
			SIF CFLAG:COUNT:1000 < 4
				RESETCOLOR
		ENDIF
		TRYCALLFORM DISPLAY_SET_{P:55}_CHARA_AFFIX

;----------キャラクター番号および氏名表示
		PRINTFORM [{COUNT,STRLENS(TOSTR(CHARANUM)),RIGHT}]
		STRLENFORM %NAME:COUNT%
		IF RESULT > 16
			PRINTFORM %CALLNAME:COUNT,16,LEFT%
		ELSE
			PRINTFORM %NAME:COUNT,16,LEFT%
		ENDIF

;----------ここよりパラメーター表示処理（引数）
		IF displayFunc != ""
			TRYCALLFORM %displayFunc%, ARG
		ELSE
			TRYCALLFORM DISPLAY_SET%setNumStr%_ARGUMENT, ARG
		ENDIF
		PRINTL

;----------ここまで
		RESETCOLOR

;----------リスト整理カウント
		P:54 += 1

	ENDIF
REND

;----------リスト整理表示部
IF (FLAG:93 / viewCount) == 1
	REPEAT viewCount - P:54
		PRINTL
	REND
ENDIF
P:54 = 0

;----------ページ分割表示部
DRAWLINE
IF P:52 > viewCount
	IF P:53 > 0
		PRINTFORM [996] - 이전 페이지로 돌아온다
	ELSE
		PRINT
	ENDIF
	PRINT
	IF P:52 > P:53 + viewCount
		PRINTFORM [997] - 다음 페이지로 나아간다
	ELSE
		PRINT
	ENDIF
ENDIF
PRINTL
DRAWLINE

;----------戻り表示部
IF ARG == 14
	PRINTFORML [999] - 양자로 보낸다
ELSEIF ARG == 16 && (P > 0 && P < 7)
	PRINTFORML [999] - 그만둔다
ELSEIF ARG == 16 && (P == 9 || P == 10)
	PRINTFORML [998] - 아무나
	PRINTFORML [999] - 돌아온다
ELSE
	PRINTFORML [999] - 돌아온다
ENDIF
DRAWLINE

;----------オプション表示部
IF ARG == 1 || ARG == 2 && E >= 1
	PRINTL 　　　　☆：조교중　★：조수　○：조수가능　●：원조수　를 나타냅니다
	DRAWLINE
ENDIF

;----------入力処理部
$INPUT_LOOP
INPUT

;----------ページ分割用共通処理
IF RESULT == 999
	P:56 = 0
	RETURN 999
ELSEIF P:53 > 0 && RESULT == 996
	SIF ARG == 5
		X = 0
	P:52 = 0
	P:53 -= viewCount
	GOTO LOOP_DISPLAY
ELSEIF P:52 > P:53 + viewCount && RESULT == 997
	SIF ARG == 5
		X = 0
	P:52 = 0
	P:53 += viewCount
	GOTO LOOP_DISPLAY
ENDIF

IF ARG >= 4 && ARG <= 6
	;不正数値弾き
	IF RESULT < 0 || RESULT > CHARANUM
		P:52 = 0
		GOTO LOOP_DISPLAY
	ELSEIF CFLAG:RESULT:199 != ARG
		P:52 = 0
		GOTO LOOP_DISPLAY
	ENDIF
ENDIF

IF filterFunc != ""
	SIF COUNT < 0 || CHARANUM < COUNT
		GOTO LOOP_DISPLAY
	SIF !EVALUATE(filterFunc,RESULT)
		GOTO LOOP_DISPLAY
ENDIF

;----------ここより関数処理(入力結果分岐)
;この処理以後、ARGの値が共通関数の第1引数から
;入力されたRESULTの値に変更される
;SET08はALL_CHARA_RESULTで代用

TRYCCALLFORM DISPLAY_SET%setNumStr%_RESULT , RESULT
CATCH
	CALL ALL_CHARA_RESULT, RESULT
ENDCATCH

;----------ここまで

;----------GOTO処理部
IF L:21 == 2
	P:52 = 0
	GOTO LOOP_DISPLAY
ENDIF

;----------後処理

				;能力／プロフ閲覧時以外はページ履歴をクリア
IF P:55 == 2 || P:55 == 8
	P:56 = P:53
ELSEIF P:55 == 16 && (P == 11 || P == 13)
	P:56 = P:53
ELSE
	P:56 = 0
ENDIF

C = RESULT			;共通関数の出입に、必ずRESULT結果：999の場合の
				;戻り処理を追加することを忘れずに！
RETURN RESULT


code:
;------------------------------------------------------------------------------
;	DISPLAY_EX_CONDITION.ERB　表示共通関数用抽出条件ファイル v0.01
;
;	導入対象バリアント：	era_inSchoolA ver0.08
;	バリアント製作者：	inSchool ◆ALP/BZZ2kc 様
;	文責：			不眠症の旅人（271）
;				タブ幅推奨：8　改行文字数推奨：80
;
;	更新内容：
;		2014/05/13	各関数に引数を渡せるように変更。引数を省略した場合は従来通りCOUNTで判定を行う。
;
;------------------------------------------------------------------------------

;各関数の『L:21 = 1』は、REPEAT文中の「CONTINUE」の役割を果たす

;----------主人抽出
@NOT_MASTER(ARG = -1)			;MASTERを除く
SIF ARG == -1
	ARG = COUNT
SIF ARG == MASTER
	L:21 = 1

@NOT_NONMASTER(ARG = -1)			;MASTERのみ(ほとんど使用する機会はない)
SIF ARG == -1
	ARG = COUNT
SIF ARG != MASTER
	L:21 = 1

;----------調教対象抽出
@NOT_TARGET(ARG = -1)			;調教対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:1000 == 5
	L:21 = 1

@NOT_NONTARGET(ARG = -1)			;調教対象のみ
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:1000 != 5
	L:21 = 1

;----------陥落素質系抽出
;●교제系
@NOT_ALLLOVER(ARG = -1)			;全교제対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:교제
	L:21 = 1

@NOT_LOVER(ARG = -1)			;교제陥落対象を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:연모 != 0 || TALENT:ARG:친애 != 0
	L:21 = 1

@NOT_NONLOVER(ARG = -1)			;교제陥落対象のみ
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:연모 == 0 && TALENT:ARG:친애 == 0
	L:21 = 1

@NOT_RENBO(ARG = -1)			;연모対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:연모 != 0
	L:21 = 1

@NOT_SHINAI(ARG = -1)			;친애対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:친애 != 0
	L:21 = 1
@NOT_ROSHUTULOVER(ARG = -1)			;全교제対象者で、노출증3以下なら除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:교제 && ABL:ARG:8 <= 3
	L:21 = 1

;●강간／협박系
@NOT_ALLSURRENDER(ARG = -1)		;全강간／협박対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:강간 || TALENT:ARG:협박
	L:21 = 1

@NOT_GOHKAN(ARG = -1)			;강간対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:강간
	L:21 = 1

@NOT_KYOHAKU(ARG = -1)			;협박対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:협박
	L:21 = 1

@NOT_SURRENDER(ARG = -1)			;강간／협박陥落対象を除く
SIF ARG == -1
	ARG = COUNT
SIF IS_NOTLOVE_FALLEN(ARG)
	L:21 = 1

@NOT_NONSURRENDER(ARG = -1)		;강간／협박陥落対象のみ
SIF ARG == -1
	ARG = COUNT
SIF !IS_NOTLOVE_FALLEN(ARG)
	L:21 = 1

@NOT_GEN_INRAN(ARG = -1)			;음란系統（음란／창녀）対象を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:음란 != 0 || TALENT:ARG:창녀 != 0
	L:21 = 1

@NOT_INRAN(ARG = -1)			;음란対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:음란 != 0
	L:21 = 1

@NOT_SHOUFU(ARG = -1)			;창녀対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:창녀 != 0
	L:21 = 1

@NOT_GEN_FUKUJU(ARG = -1)			;복종系統（복종／예속）対象を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:복종 != 0 || TALENT:ARG:예속 != 0
	L:21 = 1

@NOT_FUKUJU(ARG = -1)			;복종対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:복종 != 0
	L:21 = 1

@NOT_REIZOKU(ARG = -1)			;예속対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:예속 != 0
	L:21 = 1

@NOT_LOWSURRENDER(ARG = -1)		;下位陥落対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:음란 != 0 || TALENT:ARG:복종 != 0 || TALENT:ARG:동화
	L:21 = 1

@NOT_HIGHSURRENDER(ARG = -1)		;上位陥落対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:창녀 != 0 || TALENT:ARG:예속 != 0 || TALENT:ARG:모판
	L:21 = 1

;----------その他抽出
@NOT_CHILD_CARE(ARG = -1)			;育児対象者を除く
SIF ARG == -1
	ARG = COUNT
C = ARG
CALL CHECK_CHILD_CARE
SIF RESULT == 1
	L:21 = 1

@NOT_WORK(ARG = -1)			;労役対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:12 > 0
	L:21 = 1
SIF CFLAG:ARG:25 > 0
	L:21 = 1

@NOT_NONASSISTANT(ARG = -1)		;助손不能者を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:1 < 2
	L:21 = 1

@NOT_NONBUY(ARG = -1)			;売買／助손不能者を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:1 == 0
	L:21 = 1

@NOT_VITALITY500(ARG = -1)		;체력が500以下の者を除く
SIF ARG == -1
	ARG = COUNT
SIF BASE:ARG:0 <= 500
	L:21 = 1

@NOT_NONCHECK_TARGET(ARG = -1)		;情報収集対象外を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:1000 < 1 || CFLAG:ARG:1000 > 4
	L:21 = 1

@NOT_NONSCHOOLMATE(ARG = -1)		;他校の対象を除く
SIF ARG == -1
	ARG = COUNT
SIF !IS_GO_SAMESCHOOL(ARG)
	L:21 = 1

@NOT_PREGNANCY(ARG = -1)			;임신対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:임신 != 0
	L:21 = 1

@NOT_ASSISTANT(ARG = -1)			;助손を除く
SIF ARG == -1
	ARG = COUNT
SIF ASSI == ARG
	L:21 = 1

@NOT_KANKIN(ARG = -1)			;監禁対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:51 > 0
	L:21 = 1

@NOT_NYUIN(ARG = -1)			;入院対象者を除く
SIF ARG == -1
	ARG = COUNT
SIF CFLAG:ARG:53 > 0
	L:21 = 1

@NOT_SHISSOU(ARG = -1)			;실종者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:실종
	L:21 = 1

@NOT_DEATH(ARG = -1)			;사망者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:사망
	L:21 = 1

@NOT_LEAVE(ARG = -1)			;방출者を除く
SIF ARG == -1
	ARG = COUNT
SIF TALENT:ARG:방출
	L:21 = 1


code:
;引数無しで関数を呼び出す
@FUNC_INDEX_CALL(funcName,index)
#FUNCTION
#DIMS funcName
#DIM index
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "()")

@FUNC_STR_INDEX_CALL(funcName,index)
#FUNCTIONS
#DIMS funcName
#DIM index
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "()")

;----------------------------------------------------------------------------------------------------------
;引数1つで関数を呼び出す
;----------------------------------------------------------------------------------------------------------
@FUNC_INDEX_CALL_V(funcName,index,args1)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + ")")

@FUNC_INDEX_CALL_S(funcName,index,args1)
#FUNCTION
#DIMS funcName
#DIM index
#DIMS args1
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_STR_INDEX_CALL_V(funcName,index,args1)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIM args1
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + ")")

@FUNC_STR_INDEX_CALL_S(funcName,index,args1)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIMS args1
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + ")")

;----------------------------------------------------------------------------------------------------------
;引数2つで関数を呼び出す
;----------------------------------------------------------------------------------------------------------
@FUNC_INDEX_CALL_VV(funcName,index,args1,args2)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + ")")

@FUNC_INDEX_CALL_SV(funcName,index,args1,args2)
#FUNCTION
#DIMS funcName
#DIM index
#DIMS args1
#DIM args2
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + "," + TOSTR(args2) + ")")

@FUNC_INDEX_CALL_VS(funcName,index,args1,args2)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIMS args2
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_INDEX_CALL_SS(funcName,index,args1,args2)
#FUNCTION
#DIMS funcName
#DIM index
#DIMS args1
#DIMS args2
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_STR_INDEX_CALL_VV(funcName,index,args1,args2)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + ")")

@FUNC_STR_INDEX_CALL_SV(funcName,index,args1,args2)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIMS args1
#DIM args2
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + "," + TOSTR(args2) + ")")

@FUNC_STR_INDEX_CALL_VS(funcName,index,args1,args2)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIM args1
#DIMS args2
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_STR_INDEX_CALL_SS(funcName,index,args1,args2)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIMS args1
#DIMS args2
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + ")")

;----キリがないのでここから先は必要に応じて作る
;----------------------------------------------------------------------------------------------------------
;引数3つで関数を呼び出す
;----------------------------------------------------------------------------------------------------------
@FUNC_INDEX_CALL_VVV(funcName,index,args1,args2,args3)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
#DIM args3
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + "," + TOSTR(args3) + ")")

@FUNC_INDEX_CALL_VSS(funcName,index,args1,args2,args3)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIMS args2
#DIMS args3
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args3 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_INDEX_CALL_VVS(funcName,index,args1,args2,args3)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
#DIMS args3
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + "," + GET_CHAR_DBLQUOTE() + args3 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_INDEX_CALL_SVV(funcName,index,args1,args2,args3)
#FUNCTION
#DIMS funcName
#DIM index
#DIMS args1
#DIM args2
#DIM args3
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + GET_CHAR_DBLQUOTE() + args1 + GET_CHAR_DBLQUOTE() + "," + TOSTR(args2) + "," + TOSTR(args3) + ")")

@FUNC_STR_INDEX_CALL_VSS(funcName,index,args1,args2,args3)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIM args1
#DIMS args2
#DIMS args3
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args3 + GET_CHAR_DBLQUOTE() + ")")

@FUNC_STR_INDEX_CALL_VVS(funcName,index,args1,args2,args3)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
#DIMS args3
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + "," + GET_CHAR_DBLQUOTE() + args3 + GET_CHAR_DBLQUOTE() + ")")

;----------------------------------------------------------------------------------------------------------
;引数4つで関数を呼び出す
;----------------------------------------------------------------------------------------------------------
@FUNC_INDEX_CALL_VVVV(funcName,index,args1,args2,args3,args4)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
#DIM args3
#DIM args4
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + "," + TOSTR(args3) + "," + TOSTR(args4) + ")")

;----------------------------------------------------------------------------------------------------------
;引数5つで関数を呼び出す
;----------------------------------------------------------------------------------------------------------

;----------------------------------------------------------------------------------------------------------
;引数6つで関数を呼び出す
;----------------------------------------------------------------------------------------------------------
@FUNC_INDEX_CALL_VVVVVV(funcName,index,args1,args2,args3,args4,args5,args6)
#FUNCTION
#DIMS funcName
#DIM index
#DIM args1
#DIM args2
#DIM args3
#DIM args4
#DIM args5
#DIM args6
RETURNF EVALUATE(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + TOSTR(args2) + "," + TOSTR(args3) + "," + TOSTR(args4)  + "," + TOSTR(args5) + "," + TOSTR(args6) + ")")

@FUNC_STR_INDEX_CALL_VSSSSS(funcName,index,args1,args2,args3,args4,args5,args6)
#FUNCTIONS
#DIMS funcName
#DIM index
#DIM args1
#DIMS args2
#DIMS args3
#DIMS args4
#DIMS args5
#DIMS args6
RETURNF EVALUATE_STR(funcName + "_" + TOSTR(index) + "(" + TOSTR(args1) + "," + GET_CHAR_DBLQUOTE() + args2 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args3 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args4 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args5 + GET_CHAR_DBLQUOTE() + "," + GET_CHAR_DBLQUOTE() + args6 + GET_CHAR_DBLQUOTE() + ")")


code:
@INIT_LIST(targetList,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
VARSET targetList,defaultValue
RETURNF 1

;最終の要素を返す。-1:空のリスト
@GET_LIST_LAST_ELEMENT(targetList,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM answer
answer = FINDELEMENT(targetList,defaultValue)
SIF answer == -1
	RETURNF VARSIZE("targetList") - 1
;空のリストの場合、answer = 0なので-1すれば仕様を満たす。
RETURNF answer - 1

@LIST_ADD(targetList,addValue,addIndex = -1,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM addValue
#DIM addIndex
#DIM lastElement
SIF addValue == defaultValue
	THROW defaultValueと同じ値は追加できません。 : {addValue}
lastElement = GET_LIST_LAST_ELEMENT(targetList,defaultValue)
SIF lastElement == VARSIZE("targetList") - 1
	THROW リストが一杯です。 : {lastElement + 1} / {VARSIZE("targetList")}
IF addIndex == -1
	targetList:(lastElement + 1) = addValue
	addIndex = lastElement + 1
ELSE
	ARRAYSHIFT targetList,1,defaultValue,addIndex
	targetList:addIndex = addValue
ENDIF
RETURNF addIndex

@LIST_DELETE(targetList,deleteIndex,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM deleteIndex
#DIM deletedValue
deletedValue = targetList:deleteIndex
ARRAYSHIFT targetList,-1,defaultValue,deleteIndex
RETURNF deletedValue

@LIST_DELETE_VALUE(targetList,deleteValue,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM deleteValue
#DIM deleteIndex
deleteIndex = LIST_GET_VALUE_INDEX(targetList,deleteValue,,,defaultValue)
SIF deleteIndex == -1
	RETURNF -1
deleteValue = LIST_DELETE(targetList,deleteIndex,defaultValue)
RETURNF deleteIndex

@LIST_DELETE_VALUE_ALL(targetList,deleteIndex,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM deleteValue
#DIM deleteIndex
WHILE 1
	deleteIndex = LIST_GET_VALUE_INDEX(targetList,deleteValue,,,defaultValue)
	SIF deleteIndex == -1
		BREAK
	deleteIndex = LIST_DELETE(targetList,deleteIndex,defaultValue)
WEND
RETURNF 1

;valueは配列の中の要素
@LIST_SORT(targetList,sortRule = "value",isDescend = 0,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIMS sortRule
#DIM isDescend
#DIM gnome ;ノームの位置
#DIM elementCount
#DIMS sortFunc
elementCount = GET_LIST_LAST_ELEMENT(targetList,defaultValue) + 1
gnome = 1
sortFunc = \@ isDescend ? >= # <= \@
WHILE gnome < elementCount
	IF GROUPMATCH(COMPARE(EVALUATE(sortRule,,targetList:(gnome - 1)),EVALUATE(sortRule,,targetList:gnome)),0,(isDescend ? -1 # 1))
		gnome++
	ELSE
		SWAP targetList:(gnome - 1),targetList:gnome
		gnome = MAX(gnome - 1,1)
	ENDIF
WEND
RETURNF 1

@LIST_UNIQUE(targetList,defaultValue = -1)
#DIM REF targetList
#DIM defaultValue
;未実装

@LIST_GET_VALUE_INDEX(targetList,targetValue,fromIndex = 0,toIndex = -1,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM targetValue
#DIM fromIndex
#DIM toIndex
SIF toIndex == -1
	toIndex = GET_LIST_LAST_ELEMENT(targetList,defaultValue) + 1
IF toIndex == 0
	RETURNF -1
ELSE
	RETURNF FINDELEMENT(targetList,targetValue,fromIndex,toIndex)
ENDIF

@LIST_COUNT_ITEM(targetList,targetValue,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM defaultValue
#DIM targetValue
RETURNF MATCH(targetList,targetValue,0,GET_LIST_LAST_ELEMENT(targetList,defaultValue) + 1)

@LIST_EXTRACT_RANDOMLY(targetList,answerList,rule = "1",defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM REF answerList
#DIM selectedIndexList,999
#DIMS rule
#DIM index
#DIM selectedIndex
#DIM selectedValue
#DIM maxIndex
#DIM ret
#DIM defaultValue
maxIndex = GET_LIST_LAST_ELEMENT(targetList,defaultValue)
ret = INIT_LIST(selectedIndexList,defaultValue)
FOR index,0,varSize("answerList")
	WHILE 1
		selectedIndex = RAND:(maxIndex + 1)
		selectedValue = targetList:selectedIndex
		IF FINDELEMENT(selectedIndexList,selectedIndex) == -1 && EVALUATE(rule,selectedIndex,selectedValue) && selectedValue != defaultValue
			selectedIndexList:index = selectedIndex
			answerList:index = selectedValue
			break
		ENDIF
	WEND
NEXT
RETURNF ((maxIndex + 1) > varSize("answerList") ? -1 # GET_LIST_LAST_ELEMENT(answerList) + 1)

@LIST_EXTRACT_ONE_RANDOMLY(targetList,rule = "1",defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM answerList,1
#DIMS rule
#DIM ret
#DIM defaultValue
ret = LIST_EXTRACT_RANDOMLY(targetList,answerList,rule,defaultValue)
RETURNF answerList:0

@IS_LIST_ITERABLE(targetList,index,defaultValue = -1)
#FUNCTION
#DIM REF targetList
#DIM REF index
#DIM defaultValue
index++
SIF VARSIZE("targetList") <= index
	RETURNF 0
RETURNF targetList:index != defaultValue

;---------------------------------------------

@INIT_STR_LIST(targetList,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
VARSET targetList,defaultValue
RETURNF 1

;最終の要素を返す。-1:空のリスト
@GET_STR_LIST_LAST_ELEMENT(targetList,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
#DIM answer
SIF defaultValue == ""
	defaultValue = ^$
answer = FINDELEMENT(targetList,defaultValue)
SIF answer == -1
	RETURNF VARSIZE("targetList") - 1
;空のリストの場合、answer = 0なので-1すれば仕様を満たす。
RETURNF answer - 1

@STR_LIST_ADD(targetList,addValue,addIndex = -1,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
#DIMS addValue
#DIM addIndex
#DIM lastElement
SIF addValue == defaultValue
	THROW defaultValue와 같은 값은 추가할 수 없습니다。 : %addValue%
lastElement = GET_STR_LIST_LAST_ELEMENT(targetList,defaultValue)
SIF lastElement == VARSIZE("targetList") - 1
	THROW 리스트가 찼습니다。 : {lastElement} / {VARSIZE("targetList")}
IF addIndex == -1
	targetList:(lastElement + 1) = %addValue%
	addIndex = lastElement + 1
ELSE
	ARRAYSHIFT targetList,1,defaultValue,addIndex
	targetList:addIndex = addValue
ENDIF
RETURNF addIndex

@STR_LIST_DELETE(targetList,deleteIndex,defaultValue = "")
#FUNCTIONS
#DIMS REF targetList
#DIMS defaultValue
#DIM deleteIndex
#DIMS deletedValue
deletedValue = %targetList:deleteIndex%
ARRAYSHIFT targetList,-1,defaultValue,deleteIndex
RETURNF deletedValue

@STR_LIST_DELETE_VALUE(targetList,deleteValue,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
#DIMS deleteValue
#DIM deleteIndex
deleteIndex = STR_LIST_GET_VALUE_INDEX(targetList,deleteValue,,,defaultValue)
SIF deleteIndex == -1
	RETURNF -1
deleteValue = STR_LIST_DELETE(targetList,deleteIndex,defaultValue)
RETURNF deleteIndex

@STR_LIST_DELETE_VALUE_ALL(targetList,deleteIndex,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
#DIMS deleteValue
#DIM deleteIndex
WHILE 1
	deleteIndex = STR_LIST_GET_VALUE_INDEX(targetList,deleteValue,,,defaultValue)
	SIF deleteIndex == -1
		BREAK
	deleteValue = STR_LIST_DELETE(targetList,deleteIndex,defaultValue)
WEND
RETURNF 1

@STR_LIST_SORT(targetList,defaultValue = "")
#DIMS REF targetList
#DIMS defaultValue
;未実装

@STR_LIST_UNIQUE(targetList,defaultValue = "")
#DIMS REF targetList
#DIMS defaultValue
;未実装

@STR_LIST_GET_VALUE_INDEX(targetList,targetValue,fromIndex = 0,toIndex = -1,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
#DIMS targetValue
#DIM fromIndex
#DIM toIndex
SIF toIndex == -1
	toIndex = GET_STR_LIST_LAST_ELEMENT(targetList,defaultValue)
IF toIndex == -1
	RETURNF -1
ELSE
	RETURNF FINDELEMENT(targetList,targetValue,fromIndex,toIndex)
ENDIF

@STR_LIST_COUNT_ITEM(targetList,targetValue,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIMS defaultValue
#DIMS targetValue
RETURNF MATCH(targetList,targetValue,0,GET_STR_LIST_LAST_ELEMENT(targetList,defaultValue) + 1)

@STR_LIST_EXTRACT_RANDOMLY(targetList,answerList,rule = "1")
#FUNCTION
#DIMS REF targetList
#DIMS REF answerList
#DIM selectedIndexList,999
#DIMS rule
#DIM index
#DIM selectedIndex
#DIMS selectedValue
#DIM maxIndex
#DIM ret
maxIndex = GET_STR_LIST_LAST_ELEMENT(targetList)
ret = INIT_LIST(selectedIndexList)
FOR index,0,varSize("answerList")
	WHILE 1
		selectedIndex = RAND:(maxIndex + 1)
		selectedValue = targetList:selectedIndex
		IF FINDELEMENT(selectedIndexList,selectedIndex) == -1 && EVALUATE(rule,selectedIndex,,,selectedValue)
			selectedIndexList:index = selectedIndex
			answerList:index = selectedValue
			break
		ENDIF
	WEND
NEXT
RETURNF ((maxIndex + 1) > varSize("answerList") ? -1 # GET_STR_LIST_LAST_ELEMENT(answerList) + 1)

@STR_LIST_EXTRACT_ONE_RANDOMLY(targetList,rule = "1")
#FUNCTIONS
#DIMS REF targetList
#DIMS answerList,1
#DIMS rule
#DIM ret
ret = STR_LIST_EXTRACT_RANDOMLY(targetList,answerList,rule)
RETURNF answerList:0

@IS_STR_LIST_ITERABLE(targetList,index,defaultValue = "")
#FUNCTION
#DIMS REF targetList
#DIM REF index
#DIMS defaultValue
index++
SIF VARSIZE("targetList") <= index
	RETURNF 0
RETURNF targetList:index != defaultValue


code:
@IS_FALLEN(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:연모 || TALENT:targetChara:친애 || TALENT:targetChara:음란 || TALENT:targetChara:창녀 || TALENT:targetChara:복종 || TALENT:targetChara:예속 || TALENT:targetChara:동화 || TALENT:targetChara:모판

@IS_UPPER_FALLEN(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:친애 || TALENT:targetChara:창녀 || TALENT:targetChara:예속 || TALENT:targetChara:모판

@IS_LOVING(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:연모 || TALENT:targetChara:친애

@IS_SEXMIND(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:음란 || TALENT:targetChara:창녀

@IS_SURRENDER(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:복종 || TALENT:targetChara:예속

@IS_TENTACLE(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:동화 || TALENT:targetChara:모판

@IS_NOTLOVE_ATTACKING(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:협박 || TALENT:targetChara:강간 || TALENT:targetChara:유혹 || TALENT:targetChara:기생

@IS_NOTLOVE_FALLEN(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:음란 || TALENT:targetChara:창녀 || TALENT:targetChara:복종 || TALENT:targetChara:예속 || TALENT:targetChara:동화 || TALENT:targetChara:모판

@IS_ROUTE_IN(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:교제 || TALENT:targetChara:협박 || TALENT:targetChara:강간 || TALENT:targetChara:유혹 || TALENT:targetChara:기생 || TALENT:targetChara:최면

@IS_DISAPPEARED(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF TALENT:targetChara:실종 || TALENT:targetChara:사망

@IS_UNCONTACTABLE(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
;실종中、사망、해방済、監禁中、入院中
RETURNF TALENT:targetChara:실종 || TALENT:targetChara:사망 || TALENT:targetChara:방출 || CFLAG:targetChara:51 > 0 || CFLAG:targetChara:53 > 0

@IS_RESEARCHABLE(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF CFLAG:targetChara:1000 < 4 || CFLAG:targetChara:1000 == 6 ;基礎調査中または약점を握っている途中

@IS_ASSIABLE(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF CFLAG:targetChara:1 >= 2

@IS_WORKABLE(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara < 0
	RETURNF 0
RETURNF CFLAG:targetChara:1 >= 1

@IS_WORKALLOWING(targetChara)
#FUNCTION
#DIM targetChara
RETURNF (ABL:targetChara:순종 + ABL:targetChara:욕망 >= 6) && (!TALENT:targetChara:반항적 || (ABL:targetChara:순종 >= 4 || TALENT:targetChara:복종 || TALENT:targetChara:예속)) && (!TALENT:targetChara:꿋꿋함 || (ABL:targetChara:순종 >= 4)) && ((!TALENT:targetChara:자제심 && !TALENT:targetChara:억압 && !TALENT:targetChara:저항) || (ABL:targetChara:욕망 >= 4)) && (ABL:targetChara:기교 >= 3 || ABL:targetChara:봉사정신 >= 3 || ABL:targetChara:마조끼 >= 3 || ABL:targetChara:Ｃ감각+ABL:targetChara:Ｖ감각+ABL:targetChara:Ａ감각+ABL:targetChara:Ｂ감각>= 8 || ABL:targetChara:순종 >= 5 || ABL:targetChara:욕망 >= 5)

@GET_CHARA_FALLEN_TEXT(targetChara = -1)
#FUNCTIONS
#DIM targetChara
SIF targetChara == -1
	targetChara = TARGET
SELECTCASE 1
	CASE TALENT:targetChara:친애
		RETURNF "친애"
	CASE TALENT:targetChara:연모
		RETURNF "연모"
	CASE TALENT:targetChara:예속
		RETURNF "예속"
	CASE TALENT:targetChara:복종
		RETURNF "복종"
	CASE TALENT:targetChara:창녀
		RETURNF "창녀"
	CASE TALENT:targetChara:음란
		RETURNF "음란"
	CASE TALENT:targetChara:모판
		RETURNF "모판"
	CASE TALENT:targetChara:동화
		RETURNF "동화"
	CASE TALENT:targetChara:괴뢰
		RETURNF "괴뢰"
	CASE TALENT:targetChara:최면
		RETURNF "최면"
	CASE TALENT:targetChara:붕괴
		RETURNF "붕괴"
	CASEELSE
		RETURNF "　　"
ENDSELECT

@GET_RULED_CONTACTABLE_FIRST_CHARA(rule)
#FUNCTION
#DIMS rule
RETURNF GET_RULED_FIRST_CHARA(rule + "&& !IS_UNCONTACTABLE(index)")

@GET_RULED_CONTACTABLE_CHARAS(rule,answerList)
#FUNCTION
#DIMS rule
#DIM REF answerList
RETURNF GET_RULED_CHARAS((rule + "&& !IS_UNCONTACTABLE(index)"),answerList)

@COUNT_RULED_CONTACTABLE_CHARAS(rule)
#FUNCTION
#DIMS rule
RETURNF COUNT_RULED_CHARAS(rule + "&& !IS_UNCONTACTABLE(index)")

@IS_NONEXISTABLE_CSV_CHARA_NO_RULED_CONTACTABLE(targetNo,rule)
#FUNCTION
#DIM targetNo
#DIMS rule
RETURNF IS_NONEXISTABLE_CSV_CHARA_NO_RULED(targetNo,rule + " && !IS_UNCONTACTABLE(index)")

@IS_NONEXISTABLE_CSV_CHARA_NAME_RULED_CONTACTABLE(targetName,rule)
#FUNCTION
#DIMS targetName
#DIMS rule
RETURNF IS_NONEXISTABLE_CSV_CHARA_NAME_RULED(targetName,rule + " && !IS_UNCONTACTABLE(index)")

@IS_ANOTHERSEX_OR_BISEXUAL_TARGET(target1 = -1,target2 = -1)
#FUNCTION
#DIM target1
#DIM target2
SIF target1 == -1
	target1 = MASTER
SIF target2 == -1
	target2 = TARGET
RETURNF (TALENT:target1:남자 != TALENT:target2:남자 || TALENT:target2:바이)

@IS_SAMESEX_OR_BISEXUAL_TARGET(target1 = -1,target2 = -1)
#FUNCTION
#DIM target1
#DIM target2
SIF target1 == -1
	target1 = MASTER
SIF target2 == -1
	target2 = TARGET
RETURNF (TALENT:target1:남자 == TALENT:target2:남자 || TALENT:target2:바이)

@GET_REQUESTED_ABNORMALEXP(requestValue,targetChara = -1)
#FUNCTION
#DIM requestValue
#DIM targetChara
SIF targetChara == -1
	targetChara = TARGET
RETURNF requestValue + CSVEXP(NO:targetChara,GETNUM(EXP,"이상경험"))

@IS_PARTNERNAME_EXIST(targetChara)
#FUNCTION
#DIM targetChara
RETURNF CSTR:targetChara:남친의성 == "" && CSTR:targetChara:남친이름 == ""

@IS_PARTNERNAME_CSVEXIST(charaNo)
#FUNCTION
#DIM charaNo
RETURNF CSVCSTR(charaNo,GETNUM(TALENT,"남친의성")) == "" && CSVCSTR(charaNo,GETNUM(TALENT,"남친이름")) == ""

;見た目が男性か。isPermanentlookRequiredが1の場合、【남장】だけではダメで、【성별위장】が必要
@IS_MANLOOK(targetChara,isPermanentlookRequired = 0)
#FUNCTION
#DIM targetChara
#DIM isPermanentlookRequired
;남자で성별위장なし、または남자なし(=女性)で성별위장あり
RETURNF TALENT:targetChara:남자 ^ (TALENT:targetChara:성별위장 || (!isPermanentlookRequired && TALENT:targetChara:남장))

@GET_PRIEST_TEXT(targetChara)
#FUNCTIONS
#DIM targetChara
SELECTCASE CFLAG:targetChara:1021
	CASE 0
		;神道
		RETURNF \@ IS_MANLOOK(targetChara) ? 신주 # 무녀 \@
	CASE 1
		;キリスト教
		RETURNF \@ IS_MANLOOK(targetChara) ? 신부 # 수녀 \@
	CASE 2
		;仏教
		RETURNF \@ IS_MANLOOK(targetChara) ? 승려 # 여승 \@
	CASE 3
		;いあいあ
		RETURNF "신관"
	CASEELSE
		THROW 분류가 부정합니다。：　{CFLAG:targetChara:1021}
ENDSELECT


code:
;各関数の共通ERH。ライブラリとしてバラした時に余計な定義が混在する可能性はあるが、一旦考えない

;64進数符号化用の定数
#DIMS CONST VAL_CONVERT_LIST = "01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzｱｲｳｴｵｶｷｸｹｺｻｼｽｾｿﾀﾁﾂﾃﾄﾅﾆﾇﾈﾉﾊﾋﾌﾍﾎﾏﾐﾑﾒﾓﾔﾕﾖﾜｵﾝ"

;PRINT_RULE_COLORED_STRINGのrule数定義。本来は関数内部に書くべきだが、Emuera側がエラー吐くのでこっち
#DIM CONST RULE_COLORED_STRING_RULE_COUNT = 2

;ついでに、FONTSTYLE用の定義もここに書く。これEmuera側で用意してもいいんじゃない？
#DIM CONST FONTSTYLE_NORMAL = 0
#DIM CONST FONTSTYLE_BOLD = 1
#DIM CONST FONTSTYLE_ITALIC = 2
#DIM CONST FONTSTYLE_BREAKLINE = 4
#DIM CONST FONTSTYLE_UNDERLINE = 8


code:
;上昇したPalamを元に調教のタイプを判定する
;1 - 快楽系調教(쾌Ｃ、쾌Ｖ、쾌Ａ、쾌Ｂ、윤활、욕정)
;2 - 굴복系調教(온순、굴복、치정)
;3 - 奉仕系調教(습득)
;4 - 고통系調教(고통)
;5 - 心理系調教(공포)
;6 - 반발系調教(반감、불쾌、억울、부정)
;メモ：この関数はバリアントのPalam設定に依存して、実装を変更する必要あり
@GET_COM_TYPE()
#FUNCTION
#DIM answer
SELECTCASE FINDELEMENT(UP,MAXARRAY(UP,0),0)
	CASE 0,1,2,3,4,6 ;快楽系調教
		answer = 1
	CASE 5,7,9 ;굴복系調教
		answer = 2
	CASE 8 ;奉仕系調教
		answer = 3
	CASE 10 ;고통系調教
		answer = 4
	CASE 11 ;心理系調教
		answer = 5
	CASE 12,13,14,100 ;반발系調教
		answer = 6
	CASEELSE
		answer = 0
ENDSELECT
RETURNF answer
;


code:
@GET_JUEL(targetChara,juelName,juelCount,displayPattern=1)
#DIM targetChara
#DIMS juelName
#DIM juelCount
#DIM displayPattern

JUEL:targetChara:GETNUM(Palam,juelName) += juelCount
SELECTCASE displayPattern
	CASE 1
		PRINTFORML %타겟캐릭은% {juelCount}개의 %juelName% 구슬을 얻었다。
	CASE 2
		PRINTFORML %juelName%의 구슬+{juelCount}
	CASEELSE
		;아무것도안한다
ENDSELECT

@GET_EXP(targetChara,expeName,expeCount,displayPattern=1)
#DIM targetChara
#DIMS expeName
#DIM expeCount
#DIM displayPattern

EXP:targetChara:GETNUM(exp,expeName) += expeCount
SELECTCASE displayPattern
	CASE 1
		PRINTFORML %타겟캐릭은% {expeCount}의 %조사처리(expeName,"를")% 얻었다。
	CASE 2
		PRINTFORML %expeName%+{expeCount}
	CASEELSE
		;아무것도안한다
ENDSELECT


code:
;-------------------------------------------------
;数量入力用関数　@INPUT_MANY
;ARGで最小値、ARG:1で最大値を指定
;電卓風のコンソールから数値を入力させる
;
;ARG・ARG:1　最低値あるいは最大値　順序は逆でもよい
;ARGS　オプション。とりあえずいまはログを残すのみ
;ARGS:1　例外の数値設定。範囲外でも通る数値を設定する
;		 記述方法は0/20/30/-1といったように、文字列で"/"を区切り文字とする
;-------------------------------------------------
@INPUT_MANY(ARG, ARG:1, ARGS = "ログを残す", ARGS:1)
#LOCALSIZE 3
#LOCALSSIZE 20
#DIM LINE, 1
;最初は0
LOCAL = 0
LOCAL:1 = 1
VARSET LOCALS
SPLIT ARGS:1, "/", LOCALS
LINE = LINECOUNT
$START
REDRAW 0
CLEARLINE LINECOUNT - LINE
PRINTFORML 【{LOCAL}】　《【{ARG}】 - 【{ARG:1}】》
PRINTBUTTON "[7]", "７"
PRINT
PRINTBUTTON "[8]", "８"
PRINT
PRINTBUTTON "[9]", "９"
PRINT
PRINTBUTTON "[ AC]", "AC"
PRINTL

PRINTBUTTON "[4]", "４"
PRINT
PRINTBUTTON "[5]", "５"
PRINT
PRINTBUTTON "[6]", "６"
PRINT
PRINTBUTTON "[Max]", "MAX"
PRINTL

PRINTBUTTON "[1]", "１"
PRINT
PRINTBUTTON "[2]", "２"
PRINT
PRINTBUTTON "[3]", "３"
PRINT
PRINTBUTTON "[Min]", "MIN"
PRINTL

PRINTBUTTON "[0]", "０"
PRINT
IF LOCAL:1 == -1
	PRINTBUTTON "[+]", "+"
ELSE
	PRINTBUTTON "[-]", "-"
ENDIF
PRINT
PRINTBUTTON "[ENTER]", "ENTER"
PRINTL
PRINTFORML ※키보드를 이용해서 직접 수치를 입력할 수도 있습니다
INPUTS
SELECTCASE RESULTS
	CASE "AC"
		RESTART
	CASE "+"
		LOCAL *= -1
		LOCAL:1 = 1
	CASE "-"
		LOCAL *= -1
		LOCAL:1 = -1
	CASE "MIN"
		LOCAL = ARG
	CASE "MAX"
		LOCAL = ARG:1
	CASE "０", "１", "２", "３", "４", "５", "６", "７", "８", "９"
		IF LOCAL == 0
			LOCAL = ABS(LOCAL) + TOINT(TOHALF(RESULTS)) * LOCAL:1
		ELSE
			;桁数を取る
			LOCAL:2 = 1
			WHILE LOCAL >= POWER(10, LOCAL:2)
				LOCAL:2++
				IF LOCAL:2 > 18
					PRINTFORMW 자릿수가 너무 많습니다！
					GOTO START
				ENDIF
			WEND
			LOCAL = LOCAL * 10 + TOINT(TOHALF(RESULTS))
		ENDIF
	CASE ""
		;아무것도안한다
	CASEELSE
		IF RESULTS != "ENTER"
 			FOR LOCAL:2, 0, STRLENS(RESULTS)
 				SIF GROUPMATCH(SUBSTRING(RESULTS, LOCAL:2, 1), "0", "1", "2", "3", "4", "5", "6", "7", "8", "9")
 					CONTINUE
				PRINTFORMW 입력이 이상합니다。재입력해주세요
				RESTART
 			NEXT
			LOCAL = TOINT(RESULTS)
		ENDIF
		IF RANGE(LOCAL, ARG, ARG:1) || MATCH(LOCALS, TOSTR(LOCAL))
			SIF !STRCOUNT(ARGS, "ログを残す")
				CLEARLINE LINE - LINECOUNT
			REDRAW 1
			RETURN LOCAL
		ELSE
			PRINTFORMW 수치가 범위 밖입니다。재입력해주세요
			RESTART
		ENDIF
ENDSELECT
GOTO START


code:
;-1 ････調教者 0････MASTER(MASTERNAMEを使用) それ以外･･･該当する番号のキャラ(NICKNAMEかCALLNAME)
@GET_CALL_NAME(callerNo,calleeNo,postName="")
#FUNCTIONS
#DIM callerNo
#DIM calleeNo
#DIMS answer
#DIMS postName
IF calleeNo == MASTER
	IF callerNo == MASTER
		RETURNF "자신"
	ELSEIF MASTERNAME:callerNo == ""
		SELECTCASE 1
			CASE IS_NOTLOVE_FALLEN(callerNo)
				MASTERNAME:callerNo = 주인님
			CASE TALENT:callerNo:성악 || TALENT:callerNo:무뚝뚝함
				MASTERNAME:callerNo = 당신
			CASE TALENT:callerNo:쿨함 || TALENT:callerNo:보이쉬
				MASTERNAME:callerNo = 너
			CASEELSE
				MASTERNAME:callerNo = 당신
		ENDSELECT
	ENDIF
	answer = %MASTERNAME:callerNo%
ELSE
	IF NICKNAME:calleeNo == ""
		IF postName != ""
			answer = %CALLNAME:calleeNo%%postName%
		ELSE
			;個別設定処理が超重いため、こちらでは汎用設定のみ。RL側と違ってCSVキャラのみ&周回ありなので、最悪CSV直書きに変更する
			answer = %GET_RELATIONAL_CALLNAME(callerNo,calleeNo)%
		ENDIF
	ELSE
		answer = %NICKNAME:calleeNo%
	ENDIF
ENDIF
RETURNF answer

@GET_REVERSIBLE_RELATION_TYPE(callerNo,calleeNo)
#FUNCTION
#DIM callerNo
#DIM calleeNo
#DIM relationType
relationType = GET_RELATION_TYPE(callerNo,calleeNo)
SIF relationType != -1
	RETURNF relationType
relationType = REVERSE_RELATION(GET_RELATION_TYPE(calleeNo,callerNo))
RETURNF relationType

;素質に応じて呼び方を生成して返す汎用関数
@GET_RELATIONAL_CALLNAME(callerNo,calleeNo)
#FUNCTIONS
#DIM callerNo
#DIM calleeNo
#DIMS DYNAMIC answer = ""
#DIM relationType
relationType = GET_REVERSIBLE_RELATION_TYPE(callerNo,calleeNo)
IF relationType != -1
	answer = %GET_RELATION_TEXT(relationType,callerNo,calleeNo)%
	SIF answer == ""
		answer = %GET_DEFAULTCALL_TEXT(callerNo,calleeNo)%
ELSE
	answer = %GET_DEFAULTCALL_TEXT(callerNo,calleeNo)%
ENDIF
RETURNF answer

; 0-友人,       1-親友,     2-姉(血縁あり), 3-姉(血縁なし), 4-妹(血縁あり), 5-妹(血縁なし), 6-親(血縁あり), 7-親(血縁なし), 8-娘(血縁あり), 9-娘(血縁なし),
;10-叔母・伯母,11-姪,      12-親族,        13-教え子,      14-恩師,        15-先輩,        16-後輩,        17-主人,        18-従者,        19-想い人.     ,
;20-恋人      ,21-幼なじみ 22-同僚,        23-好敵손
@REVERSE_RELATION(relationType)
#FUNCTION
#DIM relationType
#DIM answer
#DIM relationPattern
relationPattern = relationType % SAMEHOME_PREFIX
;数字遊びの集合体。FW化した方が솔직かもなぁ
SELECTCASE relationPattern
	CASE -1 ;関係なしならNOPしておく
		RETURNF -1
	CASE 0,1,12,19 TO 23 ;友人・親友・親族、想い人、恋人、幼なじみ、同僚、好敵손はそのまま
		answer = relationPattern
	CASE 2 TO 5 ;姉妹は第2,第3bitを反転する
		answer = relationPattern ^ 6
	CASE 6 TO 9 ;姉妹は第2,3,4bitを反転する
		answer = relationPattern ^ 14
	CASE 10 TO 11 ;伯母と姪は最下位bitの反転
		answer = relationPattern ^ 1
	CASE 13 TO 18;教え子と恩師、先輩と後輩、主人と従者は偶数と奇数を入れ替える
		answer = relationPattern + (relationPattern % 2) * 2 - 1
	CASEELSE
		THROW 부정한 관계설정입니다 : {relationType}
ENDSELECT
RETURNF answer + (relationType >= SAMEHOME_PREFIX) * SAMEHOME_PREFIX

@GET_RELATION_TEXT(relationType,callerNo,calleeNo)
#FUNCTIONS
#DIM relationType
#DIM callerNo
#DIM calleeNo
#DIMS answer
SELECTCASE 1
	;呼ばれる側が姉の場合
	CASE relationType == 2 || relationType == 3
		IF TALENT:callerNo:프라이드높음 || TALENT:callerNo:건방짐 || TALENT:callerNo:보이쉬 || TALENT:callerNo:색기 || TALENT:callerNo:천연 || TALENT:callerNo:기가셈 || TALENT:callerNo:음험
			answer = \@ TALENT:calleeNo:남자 ? 오라버니 # 언니 \@
		ELSE
			answer = \@ TALENT:calleeNo:남자 ? 오빠 # 언니 \@
		ENDIF
	;呼ばれる側が親の場合
	CASE relationType == 6 || relationType == 7
		IF TALENT:callerNo:영애
			answer = \@ TALENT:calleeNo:남자 ? 아버 # 어머 \@님
		ELSEIF TALENT:callerNo:프라이드높음 || TALENT:callerNo:건방짐 || TALENT:callerNo:보이쉬 || TALENT:callerNo:색기 || TALENT:callerNo:천연 || TALENT:callerNo:기가셈 || TALENT:callerNo:음험
			answer = \@ TALENT:calleeNo:남자 ? 아버지 # 어머니 \@
		ELSE
			answer = \@ TALENT:calleeNo:남자 ? 아빠 # 엄마 \@
		ENDIF
	;呼ばれる側が恩師の場合
	CASE relationType == 14
		answer = 선생님
	;呼ばれる側が教え子の場合
	CASE relationType == 13
		answer = %GET_FAMILYNAME(calleeNo)%씨
	;呼ばれる側が先輩の場合
	CASE relationType == 15
		answer = %CALLNAME:calleeNo%선배
	;呼ばれる側が主人の場合
	CASE relationType == 17
		answer = \@ TALENT:calleeNo:남자 ? 도련님 # 아가씨 \@
	;呼ばれる側が妹、娘の場合
	CASE relationType == 4 || relationType == 5 || relationType == 8 || relationType == 9
		answer = %CALLNAME:calleeNo%
	;呼ばれる側が同僚の場合
	CASE relationType == 22
		IF TALENT:callerNo:교사 && TALENT:calleeNo:교사
			answer = %GET_FAMILYNAME(calleeNo)% 선생님
		ELSE
			answer = %GET_FAMILYNAME(calleeNo)%씨
		ENDIF
	CASEELSE
		;空文字列を返す=汎用生成処理を呼ぶ
		answer =
ENDSELECT
RETURNF answer

;素質や연령から汎用的な呼び方を生成する関数
@GET_DEFAULTCALL_TEXT(callerNo,calleeNo)
#FUNCTIONS
#DIM callerNo
#DIM calleeNo
#DIMS answer
SELECTCASE 1
	;呼ぶ側が겁쟁이、솔직、얌전함、陰気の場合
	CASE TALENT:callerNo:겁쟁이 || TALENT:callerNo:솔직 || TALENT:callerNo:얌전함  || TALENT:callerNo:무기력
		IF TALENT:calleeNo:연령 < 0
			answer = %CALLNAME:calleeNo%\@ TALENT:calleeNo:남자 ? 군 # 양 \@
		ELSE
			answer = %CALLNAME:calleeNo%씨
		ENDIF
	;呼ぶ側が반항적、건방짐、無愛想、불량の場合
	CASE TALENT:callerNo:반항적 || TALENT:callerNo:건방짐 || TALENT:callerNo:불량
		answer = %CALLNAME:calleeNo%
	CASE TALENT:callerNo:연령 < TALENT:calleeNo:연령
		answer = %CALLNAME:calleeNo%씨
	CASE TALENT:callerNo:연령 == TALENT:calleeNo:연령
		answer = %CALLNAME:calleeNo%
	CASE TALENT:callerNo:연령 > TALENT:calleeNo:연령
		answer = %CALLNAME:calleeNo%\@ TALENT:calleeNo:남자 ? 군 # 양 \@
	CASEELSE
		answer = %CALLNAME:calleeNo%씨
ENDSELECT
RETURNF answer

;INDEXのCALLNAMEまたはNAMEが一致すれば1を返すラッパー関数
@IS_CSVCHARA_NAME(charaIndex,nameValue)
#FUNCTION
#DIM charaIndex
#DIMS nameValue
RETURNF NAME:charaIndex == nameValue || CALLNAME:charaIndex == nameValue

@GET_FAMILYNAME(charaIndex)
#FUNCTIONS
#DIM charaIndex
RETURNF \@ TALENT:charaIndex:외국인 ? %GET_NAME_RIGHTELEMENT(charaIndex)% # %GET_NAME_LEFTELEMENT(charaIndex)% \@

@GET_FIRSTNAME(charaIndex)
#FUNCTIONS
#DIM charaIndex
RETURNF \@ TALENT:charaIndex:외국인 ? %GET_NAME_LEFTELEMENT(charaIndex)% # %GET_NAME_RIGHTELEMENT(charaIndex)% \@

@GET_NAME_LEFTELEMENT(charaIndex)
#FUNCTIONS
#DIM charaIndex
IF STRCOUNT(NAME:charaIndex,"　") > 0
	RETURNF SUBSTRING(NAME:charaIndex,0,STRFIND(NAME:charaIndex,"　")-1)
ELSE
	RETURNF SUBSTRING(NAME:charaIndex,0,STRFIND(NAME:charaIndex," ")-1)
ENDIF

@GET_NAME_RIGHTELEMENT(charaIndex)
#FUNCTIONS
#DIM charaIndex
IF STRCOUNT(NAME:charaIndex,"　") > 0
	RETURNF SUBSTRING(NAME:charaIndex,STRFIND(NAME:charaIndex,"　")+2)
ELSE
	RETURNF SUBSTRING(NAME:charaIndex,STRFIND(NAME:charaIndex," ")+1)
ENDIF


code:
;立っているビット数を数える
@COUNT_BIT(targetValue)
#FUNCTION
#DIM targetValue
#DIM DYNAMIC answer = 0
WHILE targetValue != 0
	answer += targetValue & 1
	targetValue = targetValue >> 1
WEND
RETURNF answer

;64進数(0～9、A～Z、a～z、/、$の1文字で0～63までの数字を表す記法)からINTへ変換する。今のところ1文字前提だが、必要に応じ拡張する
;솔직にBASE64で書けって？　せやな
@FROM_4F_TO_INT(targetValue)
#FUNCTION
#DIMS targetValue
#DIM answer
SELECTCASE ENCODETOUNI(targetValue)
	CASE ENCODETOUNI("0") TO ENCODETOUNI("9")
		answer = ENCODETOUNI(targetValue) - ENCODETOUNI("0")
	CASE ENCODETOUNI("A") TO ENCODETOUNI("Z")
		answer = ENCODETOUNI(targetValue) - ENCODETOUNI("A") + 10
	CASE ENCODETOUNI("a") TO ENCODETOUNI("z")
		answer = ENCODETOUNI(targetValue) - ENCODETOUNI("a") + 36
	CASE ENCODETOUNI("/")
		answer = 62
	CASE ENCODETOUNI("$")
		answer = 63
	CASEELSE
		THROW 문자가 부정합니다 : %targetValue%
ENDSELECT
RETURNF answer

;INTから64進数へ変換する(未実装)
@FROM_INT_TO_4F(targetValue)
#FUNCTIONS
#DIMS targetValue
RETURNF ""

;与えられた値を比較し、target1 < target2なら1、target1 == target2なら0、target1 > target2なら-1を返すラッパー関数
@COMPARE(target1,target2)
#FUNCTION
#DIM target1
#DIM target2
RETURNF (target1 == target2 ? 0 # (target2 - target1) / ABS(target2 - target1))

@ROUNDDOWN(value,digit)
#FUNCTION
#DIM value
#DIM digit
RETURNF (value / POWER(10,digit) * POWER(10,digit))

@ROUNDUP(value,digit)
#FUNCTION
#DIM value
#DIM digit
RETURNF ROUNDDOWN(value + POWER(10,digit) - 1,digit)

@ROUND(value,digit)
#FUNCTION
#DIM value
#DIM digit
;未実装
RETURNF 0

@LOG2(value)
#FUNCTION
#DIM value
RETURNF LOG(POWER(value,8))/LOG(POWER(2,8))

@GET_PALAM_LV(palamNameStr)
#FUNCTION
#DIMS palamNameStr
#DIM maxLv = 0 ;キャッシュしておく
IF maxLv == 0
	FOR maxLV,1,VARSIZE("PALAMLV")
		SIF PALAMLV:maxLV == 0
			BREAK
	NEXT
ENDIF
RETURNF GETPALAMLV(PALAM:GETNUM(PALAM,palamNameStr),maxLV - 1)

;targetValueの先頭fromBit目よりrangeビットを取り出す。当然だがfromBit+rangeが65以上となるとアンダーフローしておかしな結果を返す
@GET_BIT_RANGE(targetValue,fromBit,range)
#FUNCTION
#DIM targetValue
#DIM fromBit
#DIM range
RETURNF (targetValue >> (64 - fromBit - range)) & (POWER(2,range) - 1)

@WHICH(value1,value2,rule)
#FUNCTION
#DIM value1
#DIM value2
#DIMS rule
SELECTCASE EVALUATE(rule,1,value1) * 2 + EVALUATE(rule,2,value2)
	CASE 3,2
		RETURNF value1
	CASE 1
		RETURNF value2
	CASEELSE
		RETURNF 0
ENDSELECT


code:
;特定キャラの通っている学園を返す。주부・사회인・学外キャラの場合は-1を返す(CFLAG参照)
@GET_CHARA_GO_SCHOOL_INDEX(targetChara)
#FUNCTION
#DIM targetChara
SIF CFLAG:targetChara:1001 == 0
	RETURNF -1
RETURNF CFLAG:targetChara:1001

;特定キャラの所属学園を返す。80000番台の場合は-1を返す(NO参照)
@GET_CHARA_BELONG_SCHOOL_INDEX(targetChara)
#FUNCTION
#DIM targetChara
;MASTERはキャラ番号ではなく、実際に通っている学園に所属している扱い
SIF targetChara == MASTER
	RETURNF GET_CHARA_GO_SCHOOL_INDEX(targetChara)
SIF NO:targetChara >= 80000
	RETURNF -1
RETURNF (NO:targetChara / 100) + 1

;キャラ同士が同じ学園に通っているか判定する。第二引数を省略するとMASTERとみなす(CFLAG参照)
@IS_GO_SAMESCHOOL(targetChara,anotherChara = 0)
#FUNCTION
#DIM targetChara
#DIM anotherChara
SIF GET_CHARA_GO_SCHOOL_INDEX(targetChara) == -1 || GET_CHARA_GO_SCHOOL_INDEX(anotherChara) == -1
	RETURNF 0
RETURNF GET_CHARA_GO_SCHOOL_INDEX(targetChara) == GET_CHARA_GO_SCHOOL_INDEX(anotherChara)

;キャラ同士が同じ学園に所属しているか判定する。第二引数を省略するとMASTERとみなす(NO参照)
@IS_BELONG_SAMESCHOOL(targetChara,anotherChara = 0)
#FUNCTION
#DIM targetChara
#DIM anotherChara
SIF GET_CHARA_BELONG_SCHOOL_INDEX(targetChara) == -1 || GET_CHARA_BELONG_SCHOOL_INDEX(anotherChara) == -1
	RETURNF 0
RETURNF GET_CHARA_BELONG_SCHOOL_INDEX(targetChara) == GET_CHARA_BELONG_SCHOOL_INDEX(anotherChara)

;学校名を返す
@GET_SCHOOL_NAME(index)
#FUNCTIONS
#DIM index
RETURNF FUNC_STR_INDEX_CALL("SCHOOL_DATA_NAME",index)

;学校説明文を表示する
@PRINT_SCHOOL_COMMENT(index)
#DIM index
CALLFORM SCHOOL_DATA_COMMENT_{index}()

;男子校なら1を返す
@IS_BOYSSCHOOL(index)
#FUNCTION
#DIM index
RETURNF ((GET_SCHOOL_CATEGORY(index) & 3) == 2)

;女子校なら1を返す
@IS_GIRLSSCHOOL(index)
#FUNCTION
#DIM index
RETURNF ((GET_SCHOOL_CATEGORY(index) & 3) == 1)

;共学なら1を返す
@IS_CO_EDUCATION_SCHOOL(index)
#FUNCTION
#DIM index
RETURNF ((GET_SCHOOL_CATEGORY(index) & 3) == 3)

;男子が通える学校なら1を返す。転入時に여장도구の要否で使用
@IS_BOYS_GOING_SCHOOL(index)
#FUNCTION
#DIM index
RETURNF ((GET_SCHOOL_CATEGORY(index) & 2) == 2)

;女子が通える学校なら1を返す。使い道？　知らん
@IS_GIRLS_GOING_SCHOOL(index)
#FUNCTION
#DIM index
RETURNF ((GET_SCHOOL_CATEGORY(index) & 1) == 1)

;男子校か女子校か、通っている学生は何かを帰す。
;通常は他のラッパー関数を使う前提。ラッパー関数がないなら適宜追加
@GET_SCHOOL_CATEGORY(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_CATEGORY",index)

;사립校か
@IS_PRIVATESCHOOL(index)
#FUNCTION
#DIM index
RETURNF (FUNC_INDEX_CALL("SCHOOL_DATA_CATEGORY",index) & 12) == 0

;공립校か
@IS_PUBLICSCHOOL(index)
#FUNCTION
#DIM index
RETURNF !IS_PRIVATESCHOOL(index) && !IS_NATIONALSCHOOL(index)

;국립校か
@IS_NATIONALSCHOOL(index)
#FUNCTION
#DIM index
RETURNF (FUNC_INDEX_CALL("SCHOOL_DATA_CATEGORY",index) & 12) == 12

;寮があるか。0 - 寮なし、1 - 寮あり(通いとの選択なのでちょっと生活費が上がる)、2 - 全寮制(生活費がとってもお安い)
@GET_DORMITRY_CLASS(index)
#FUNCTION
#DIM index
RETURNF (((FUNC_INDEX_CALL("SCHOOL_DATA_CATEGORY",index) & 48) >> 4) + 1) / 2

;通っている学生の区分。1ビット目:초등학생、2ビット目:중학생、3ビット目:고등학생、4ビット目:대학생。流石に유치園児を抱こうとするHENTAIはいないはず
;例：1 = 小学校、2 = 中学校、4 = 高校、8 = 大学、6 = 中高一貫
@GET_SCHOOL_LAYER(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_LAYER",index)

;勉強のレベル。試験の難易度に影響する。
;1 = 名前を書けば通るレベル。クロマティ学園とかがここに入る
;3 = 学生は基本頭が悪い。進学する学生はほぼおらず、大体が地元で就職する。小学校ならその地方の最低レベルの中学に進む。
;5 = 平均的な학력。卒業後は進学と就職が半々。
;7 = 進学校。卒業後はほとんど進学する。まれに超進学校や有名大学に進む学生もいる。
;10= 超進学校。卒業後はほぼ全員が進学し、その進学先も同じような超進学校・有名大学になる。将来のエリートというやつ。
@GET_SCHOOL_STUDY_LEVEL(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_STUDY_LEVEL",index)

;治安。
;1 = カオスそのもの。校内で殺人事件が起こってもおかしくないレベル
;3 = 一般的な荒れた学校(ってなんだ)。基本生徒は7割くらいいないイメージ。これ以下だと日中調教が可能になる
;5 = 普通の学校。これ以上だと夜間の学園内특수調教が可能になる。
;8 = 管理が行き届いた学校。みんな真面目に授業を受けるため、逆にそこから外れると隙が多い。これ以上だと日中の学園内특수調教が可能になる。
;10= ディストピアな学校。ガチガチに管理された統制社会。禁書の長点上機学園とか。
@GET_SCHOOL_ORDER_LEVEL(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_ORDER",index)

;規模。学生の人数。
;1 = 過疎地域の分校。全学年で1クラスくらいのレベル。
;3 = 過疎地域の学校。1学年1クラスくらい。これ以下だと부활동が選択できない(強制的に귀가부扱い)
;5 = 普通の学校。1学年4～5クラス。
;7 = 大きな学校。1学年7～9クラスほど。このレベルから専門コースが出てくる感じ。
;10= マンモス校。1学年10クラス以上。
@GET_SCHOOL_SIZE_LEVEL(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_SIZE",index)

;資金力。どれだけ設備などに金をかけているか。入学金にはねるため、基本的には学生の裕福度に比例する(特待生など例外あり)
;1 = 超가난。施設の補修すらままならない。
;3 = 가난。
;5 = 普通。
;7 = 裕福。自前で寮を構えられるだけの資金力がある。
;10= 超裕福。いわゆるお嬢様学校。
@GET_SCHOOL_WEALTH_LEVEL(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_WEALTH",index)

;技術レベル。
;1 = 超時代遅れ。パソコンなにそれとかそんなレベル
;3 = 時代遅れ。パソコンとかは一応最低限の台数がある。けどボロいし、電算機室とかそんな名前。
;5 = 普通。パソコンなど一通りの設備は揃っている。
;7 = 未来的。タブレットを一人一台が当たり前で、生徒情報の管理にも活用されている。
;10= 超未来的。未来ものによくある謎技術が普通に転がっている。
@GET_SCHOOL_TECH_LEVEL(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_TECH_LEVEL",index)

;周辺の発展度
;1 = ド田舎。何故学校があるのか謎なレベル。廃校も近い
;3 = 田舎。学生よりタヌキの方が多いとかそんなレベル。このあたりまで山や川などが移動先に入る。
;5 = 地方都市。一学年を作れるくらいには人입が多い。でもやっぱり移動には車が必須。このあたりから역전번화가ができる。ショボいけど
;7 = 地方中枢都市。このくらいから、車だと渋滞につかまるのでバスや전차がメインになってくる。アミューズメント施設なんかができる
;10= 都心。道ばたの石ころより人が多い。何故学校があるのか謎なレベル。つーか土地もったいねえ
@GET_SCHOOL_AROUND_DEVELOP_LEVEL(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_DEVELOP_LEVEL",index)

;施設。存在する場合に1
@IS_FACILITY_EXIST(facilityName,schoolIndex = -1)
#FUNCTION
#DIMS facilityName
#DIM facilityIndex
#DIM schoolLevel
#DIM answer
#DIM schoolIndex
SIF schoolIndex == -1
	schoolIndex = GET_CHARA_GO_SCHOOL_INDEX(MASTER)
facilityIndex = GET_SP_TRAIN_LOCATION_INDEX(facilityName)
SIF facilityIndex == -1
	RETURNF 0
IF GET_SP_TRAIN_LOCATION_IS_SCHOOL_FACILITY(facilityIndex)
	RETURNF INRANGE(GET_SCHOOL_SIZE_LEVEL(schoolIndex),GET_SP_TRAIN_LOCAION_REQUIRED_SCHOOL_MIN_LEVEL(facilityIndex),GET_SP_TRAIN_LOCAION_REQUIRED_SCHOOL_MAX_LEVEL(facilityIndex)) || (SEARCH_BETWEEN_STRING(FUNC_STR_INDEX_CALL("SCHOOL_DATA_SCHOOL_FACILITY",schoolIndex),",",facilityName) >= 0)
ELSE
	RETURNF INRANGE(GET_SCHOOL_AROUND_DEVELOP_LEVEL(schoolIndex),GET_SP_TRAIN_LOCAION_REQUIRED_AROUND_MIN_LEVEL(facilityIndex),GET_SP_TRAIN_LOCAION_REQUIRED_AROUND_MAX_LEVEL(facilityIndex)) || (SEARCH_BETWEEN_STRING(FUNC_STR_INDEX_CALL("SCHOOL_DATA_AROUND_FACILITY",schoolIndex),",",facilityName) >= 0)
ENDIF

;転入可否判定。男子校/女子校の区分などの汎用的要素以外の条件での転入可否を返す。1を返せば転入可能。
@IS_SCHOOL_ADMISSIONABLE(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_IS_ADMISSIONABLE",index)

;転出可否判定。転出するための条件を満たしているか判定。普通特に条件はなし
@IS_SCHOOL_TRASFERABLE(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_IS_TRASFERABLE",index)

;転入時イベントを起こす
@PRINT_SCHOOL_EVENT_ADMISSION(index)
#DIM index
CALLFORM SCHOOL_DATA_EVENT_ADMISSION_{index}()

;イベントでの追加キャラのリストを返す。"ADMISSION","SPORTS_CLUB","CULTURE_CLUB","FIGHTING_CLUB","COMITTEE","NONE_CLUB"から選択
@GET_SCHOOL_EVENT_MEETING_CHARA(index,keyword)
#FUNCTIONS
#DIM index
#DIMS keyword
RETURNF FUNC_STR_INDEX_CALL("SCHOOL_DATA_EVENT_MEETING_" + keyword,index)

;MASTERが所属している場合にのみ起きる学園固有イベントを起こす
@PRINT_SCHOOL_EVENT_SP_THIS_SCHOOL(index)
#DIM index
CALLFORM SCHOOL_DATA_EVENT_SP_THIS_SCHOOL_{index}()

;MASTERが所属していなくとも起きる学園固有イベントを起こす
@PRINT_SCHOOL_EVENT_SP_ANOTHER_SCHOOL(index)
#DIM index
CALLFORM SCHOOL_DATA_EVENT_SP_ANOTHER_SCHOOL_{index}()

@GET_SCHOOL_EVENT_SP_TRAIN_START(index)
#FUNCTIONS
#DIM index
RETURNF FUNC_STR_INDEX_CALL("SCHOOL_DATA_EVENT_SP_TRAIN_START",index)

@IS_SAME_CLUB(targetChara1 = -1,targetChara2 = -1)
#FUNCTION
#DIM targetChara1
#DIM targetChara2
SIF targetChara1 == -1
	targetChara1 = TARGET
SIF targetChara2 == -1
	targetChara2 = MASTER
SIF CFLAG:targetChara1:1002 == 0 || TALENT:targetChara1:귀가부
	RETURNF 0
SIF CFLAG:targetChara2:1002 == 0 || TALENT:targetChara2:귀가부
	RETURNF 0
RETURNF CFLAG:targetChara1:1002 == CFLAG:targetChara2:1002

@IS_SAME_CATEGORY_CLUB(targetChara1 = -1,targetChara2 = -1)
#FUNCTION
#DIM targetChara1
#DIM targetChara2
SIF targetChara1 == -1
	targetChara1 = TARGET
SIF targetChara2 == -1
	targetChara2 = MASTER
SIF CFLAG:targetChara1:1002 == 0 || TALENT:targetChara1:귀가부
	RETURNF 0
SIF CFLAG:targetChara2:1002 == 0 || TALENT:targetChara2:귀가부
	RETURNF 0
RETURNF GET_CLUB_CATEGORY(CFLAG:targetChara1:1002) == GET_CLUB_CATEGORY(CFLAG:targetChara2:1002)

;1:運動系 2:文化系 3:格闘技系 4:위원회 -1:귀가부(=0)
@GET_CLUB_CATEGORY(clubIndex)
#FUNCTION
#DIM clubIndex
SIF clubIndex == 0
	RETURNF -1
;最初の運動系クラブから順に100個間隔で並んでいるのが前提。ずれたらSELECTCASEで。
RETURNF (clubIndex - SCHOOL_CLUB_START_INDEX_SPORTS_CLUB) / 100 + 1

@GET_CLUB_USE_PALAM(targetChara)
#FUNCTION
#DIM targetChara
SIF targetChara == -1
	targetChara = MASTER
SIF GET_CLUB_CATEGORY(CFLAG:targetChara:1002) == -1
	RETURNF 0
RETURNF EVALUATE("ABL:index:" + GET_CLUB_USE_PALAM_NAME(GET_CLUB_CATEGORY(CFLAG:targetChara:1002)),targetChara)

@GET_CLUB_USE_PALAM_NAME(clubCategory)
#FUNCTIONS
#DIM clubCategory
SELECTCASE clubCategory
	CASE 1
		RETURNF "운동능력"
	CASE 2
		RETURNF "감성"
	CASE 3
		RETURNF "전투능력"
	CASE 4
		RETURNF "학력"
	CASEELSE
		THROW 부정한 Category입니다。 : {clubCategory}
ENDSELECT

;부활동名から부활동のindexを返す。見つからなければ-1。(可能性があるなら呼び元で対処すること)
@GET_CLUBINDEX_FROM_NAME(clubName)
#FUNCTION
#DIMS clubName
RETURNF FINDELEMENT(STR:0,clubName,SCHOOL_CLUB_START_INDEX_SPORTS_CLUB,SCHOOL_CLUB_END_INDEX_COMITTEE + 1,0)

;学園ごとのキャラ表示色。キャラ固有が存在する場合はそちら優先
@GET_SCHOOL_COLOR(index)
#FUNCTION
#DIM index
RETURNF FUNC_INDEX_CALL("SCHOOL_DATA_DEFAULT_COLOR",index)

;キャラごとの表示色。固有設定があればそれ。なければ学園指定の色
@GET_CHARA_COLOR(charaIndex)
#FUNCTION
#DIM charaIndex
IF CFLAG:charaIndex:195 == 0 && CFLAG:charaIndex:196 == 0 && CFLAG:charaIndex:197 == 0
	SIF GET_CHARA_GO_SCHOOL_INDEX(charaIndex) == -1
		RETURNF OUTSCHOOL_CHARA_DEFAULT_COLOR
	RETURNF GET_SCHOOL_COLOR(GET_CHARA_GO_SCHOOL_INDEX(charaIndex))
ELSE
	RETURNF COLOR_FROMRGB(CFLAG:charaIndex:195,CFLAG:charaIndex:196,CFLAG:charaIndex:197)
ENDIF

;キャラごとのSETCOLOR
@SET_CHARACOLOR(charaIndex)
#DIM charaIndex
SETCOLOR GET_CHARA_COLOR(charaIndex)

;キャラと学園の学年がどれほどズレているか。正の数ならキャラが、負の数なら学園が、それぞれ絶対値分上回っている。
@GET_LAYER_DIFFER_FROM_CHARA_AND_SCHOOL(charaIndex,schoolIndex)
#FUNCTION
#DIM charaIndex
#DIM schoolIndex
#DIM DYNAMIC answer = 0
#DIM charaLayer
#DIM schoolLayer
charaLayer = POWER(2,GET_CHARA_LAYER(charaIndex) - 1)
schoolLayer = GET_SCHOOL_LAYER(schoolIndex)
WHILE (charaLayer & schoolLayer) == 0
	IF charaLayer > schoolLayer
		charaLayer = (charaLayer >> 1)
		answer++
	ELSE
		charaLayer = (charaLayer << 1)
		answer--
	ENDIF
WEND
RETURNF answer

;キャラの実際の학력を算出。학력の値の他に、実연령と学園のレイヤーの違いを考慮
@GET_CHARA_STUDY_LEVEL(charaIndex,schoolIndex)
#FUNCTION
#DIM charaIndex
#DIM schoolIndex
RETURNF ABL:charaIndex:학력 + GET_LAYER_DIFFER_FROM_CHARA_AND_SCHOOL(charaIndex,schoolIndex)

;キャラから見て要求される학력レベルを記載。学園の학력の他に、実연령と学園のレイヤーの違いを考慮
@GET_RELATIONAL_STUDY_LEVEL(charaIndex,schoolIndex)
#FUNCTION
#DIM charaIndex
#DIM schoolIndex
RETURNF GET_SCHOOL_STUDY_LEVEL(schoolIndex) - GET_LAYER_DIFFER_FROM_CHARA_AND_SCHOOL(charaIndex,schoolIndex)


code:
;ruleを満たすキャラをselectResultの要素数分だけランダムに返す。
;ruleはSTRFORMで解釈されINT型に変換されるので、1か0を返すPRINTFORM構文で記載する。
;なお、rule内では変数indexはキャラ番号として扱われる。
;必ず要求された人数が返るとは限らない(元から足りない場合)ため、呼び元で適切に分岐すること。
;返す人数は戻り値に格納。また、空き枠には-1を代入して返すため、先頭から-1を検索してもよい。
;最終的にEVAL関数に渡されるので、グローバルな変数・関数以外使えないので注意。その場合は呼び元でリテラル化して渡す。
@GET_RANDOM_CHARAS(rule,selectResult)
#DIMS DYNAMIC rule
#DIM REF selectResult ;必要なキャラの数だけ枠を確保して呼び出す。
RETURN GET_RANDOM_CHARAS_CORE(rule,selectResult)

@GET_RANDOM_CHARAS_CORE(rule,selectResult)
#FUNCTION
#DIMS DYNAMIC rule
#DIM REF selectResult ;必要なキャラの数だけ枠を確保して呼び出す。
#DIM index
#DIM DYNAMIC filteredCharas,1000 = 0 ;とりあえず1000。足りなかったらエラーになるんで適当に増やしてください。
#DIM DYNAMIC filteredCharaCount = 0
#DIM selectedIndex

VARSET selectResult, -1

;一回走査し、条件を満たすキャラの一覧を作る。
filteredCharaCount  = GET_RULED_CHARAS(rule,filteredCharas)
SIF filteredCharaCount < 0
	THROW 추출된 캐릭터 수가 상한을 넘었습니다

IF varSize("selectResult") >= filteredCharaCount
	;枠が余るので、全部返す。
	FOR index,0,filteredCharaCount
		selectResult:index = filteredCharas:index
	NEXT
ELSE
	;枠が足りないのでランダムに抽出
	index = LIST_EXTRACT_RANDOMLY(filteredCharas,selectResult)
ENDIF
RETURNF index

;ruleを満たすキャラを先頭からselectResultの要素数分だけ返す。
;ruleを満たすキャラの総数がselectResultの要素数より多い場合、そこで探索は打ち切られ戻り値として-1を返す
;それ以外の場合、戻り値として見つかった人数を返す
;どちらの場合でもselectResultに見つかったキャラのリストを設定する。空き枠には-1を代入して返す。
@GET_RULED_CHARAS(rule,selectResult)
#FUNCTION
#DIMS DYNAMIC rule
#DIM REF selectResult
#DIM DYNAMIC filteredCharaCount = 0
#DIM index

VARSET selectResult, -1
FOR index,0,CHARANUM
	IF EVALUATE(rule,index)
		IF filteredCharaCount == varSize("selectResult")
			filteredCharaCount = -1
			BREAK
		ENDIF
		selectResult:filteredCharaCount = index
		filteredCharaCount++
	ENDIF
NEXT
RETURNF filteredCharaCount

;条件を満たすキャラからランダムで一人を返す。
;GET_RANDOM_CHARAS_COREの1名限定・引数単純化版
@GET_RULED_SINGLE_CHARA(rule)
#FUNCTION
#DIMS rule
#DIM selectResult,1
#DIM dummy
dummy = GET_RANDOM_CHARAS_CORE(rule,selectResult)
RETURNF selectResult

@GET_RULED_FIRST_CHARA(rule)
#FUNCTION
#DIMS rule
#DIM selectResult,1
#DIM dummy
dummy = GET_RULED_CHARAS(rule,selectResult)
RETURNF selectResult

;一人ならその一人の名前、複数人なら代表を一人選び、CALLNAMEに「達」を付けて返す
;一人と判定される条件は、targetsの要素数が1か、targets:1の値が負
@GET_TARGETS_CALLS(targets)
#FUNCTIONS
#DIM REF targets
#DIM index
#DIMS answer
IF VARSIZE("targets") == 1 || targets:1 < 0
	answer = %CALLNAME:(targets:0)%
ELSE
	answer = %CALLNAME:(targets:(RAND:(VARSIZE("targets"))))%達
ENDIF
RETURNF answer

@GET_ONE_TARGET_CALL(targets)
#FUNCTIONS
#DIM REF targets
#DIM index
#DIMS answer
IF VARSIZE("targets") == 1 || targets:1 < 0
	answer = %CALLNAME:(targets:0)%
ELSE
	answer = %CALLNAME:(targets:(RAND:(VARSIZE("targets"))))%
ENDIF
RETURNF answer

;ruleを満たすキャラ数を返す。それ以外はGET_RANDOM_CHARASに同じ
@COUNT_RULED_CHARAS(rule)
#FUNCTION
#DIMS rule
#DIM DYNAMIC answer=0
#DIM index
FOR index,0,CHARANUM
	IF EVALUATE(rule,index)
		answer++
	ENDIF
NEXT
RETURNF answer

;targetCharaListの中からruleの条件で結果を算出し、最大のキャラを返す。
;同値の場合はその中から一人ランダムで返す
@GET_RULED_MAXPARAM_CHARA(rule,targetCharaList)
#FUNCTION
#DIMS rule
#DIM REF targetCharaList
#DIM DYNAMIC answerList,100 ;とりあえず100。必要に応じ拡張
#DIM selectedCharaCount
selectedCharaCount = GET_RULED_RULEDPARAM_CHARA_LIST("COMPARE(value,totalizedValue)",rule,targetCharaList,answerList)
RETURNF answerList:(RAND:(selectedCharaCount + 1))

;ruleの計算結果をcompareRuleで比較し、以下の条件で集約して結果のリストを返す
;compareRuleの結果が1 : それまでの結果をクリアし、新たな値を追加する。 0 : 結果にその値を追加する。 -1 : 아무것도안한다
@GET_RULED_RULEDPARAM_CHARA_LIST(compareRule,rule,targetCharaList,answerList)
#FUNCTION
#DIMS compareRule
#DIMS rule
#DIM REF targetCharaList
#DIM REF answerList
#DIM index
#DIM DYNAMIC preCheckValue = __INT_MIN__
#DIM currentCheckValue
#DIM ret
FOR index,0,GET_LIST_LAST_ELEMENT(targetCharaList) + 1
	currentCheckValue = EVALUATE(rule,targetCharaList:index)
	SELECTCASE EVALUATE(compareRule,,currentCheckValue,preCheckValue)
		CASE 1
			ret = INIT_LIST(answerList)
			ret = LIST_ADD(answerList,targetCharaList:index)
			preCheckValue = currentCheckValue
		CASE 0
			ret = LIST_ADD(answerList,targetCharaList:index)
		CASE -1
			;아무것도안한다
		CASEELSE
			THROW compareRule의 결과가 부정합니다。 : {EVALUATE(compareRule,,currentCheckValue,preCheckValue)}
	ENDSELECT
NEXT
RETURNF GET_LIST_LAST_ELEMENT(answerList) + 1

;targetCharaListの中からruleの条件で計算し、結果の降順にソートして返す。同値の場合はindexが先のキャラ優先。溢れた分は無視。
@SORT_RULED_MAXPARAM_CHARA(rule,targetCharaList,answerList)
#FUNCTION
#DIMS rule
#DIM REF targetCharaList
#DIM REF answerList
RETURNF SORT_RULED_CHARA_LIST("COMPARE(value,totalizedValue)",rule,targetCharaList,answerList)

;compareRuleを使用してruleの結果を比較・ソートする。溢れた分は破棄。マージソートがやりにくいので挿入ソート。遅いけどしゃーない
;compareRuleの結果が-1：そこに値を挿入 0,1:아무것도안한다
@SORT_RULED_CHARA_LIST(compareRule,rule,targetCharaList,answerList)
#FUNCTION
#DIMS compareRule
#DIMS rule
#DIM REF targetCharaList
#DIM REF answerList
#DIM compareValueList,100 ;とりあえず100
#DIM index
#DIM index2
#DIM currentCompareValue
#DIM ret
SIF VARSIZE("targetCharaList") > VARSIZE("compareValueList")
	THROW 정렬 대상 리스트가 너무 큽니다。값의 결락이 발생합니다。 : {VARSIZE("targetCharaList")}
ret = INIT_LIST(answerList)
ret = INIT_LIST(compareValueList,__INT_MIN__)
FOR index,0,GET_LIST_LAST_ELEMENT(targetCharaList) + 1
	currentCompareValue = EVALUATE(rule,targetCharaList:index)
	FOR index2,0,VARSIZE("answerList")
		IF compareValueList:index2 == __INT_MIN__
			answerList:index2 = targetCharaList:index
			compareValueList:index2 = currentCompareValue
			BREAK
		ELSE
			SELECTCASE EVALUATE(compareRule,,currentCompareValue,compareValueList:index2)
				CASE 1,0
					CONTINUE
				CASE -1
					ARRAYSHIFT answerList,1,targetCharaList:index,index2
					ARRAYSHIFT compareValueList,1,currentCompareValue,index2
					BREAK
			CASEELSE
				THROW compareRule의 결과가 부정합니다。 : {EVALUATE(compareRule,,currentCompareValue,compareValueList:index2)}
			ENDSELECT
		ENDIF
	NEXT
NEXT
RETURNF 0

;evalもどき。入力文字列をSTRFORM構文として処理する。戻り値は数値形
@EVALUATE(evalString,index=-1,value=-1,totalizedValue=-1,strKey="")
#FUNCTION
#DIMS evalString
#DIM DYNAMIC index
#DIM DYNAMIC value
#DIM DYNAMIC totalizedValue
#DIMS DYNAMIC strKey
RETURNF TOINT(STRFORM("{" + evalString + "}"))

;evalもどきその2。文字列を変数名として解釈してvalueの値を代入する。
;戻り値は変更後の該当変数の値。
;内部でループをごりごり回して1ずつ加算・減算するだけ
@EVALUATE_SET(evalString,value,index=-1)
#FUNCTION
#DIMS evalString
#DIM index
#DIM value
#DIM dummy
#DIMS operand
#DIM loopIndex
IF EVALUATE(evalString,index) != value
	IF EVALUATE(evalString,index) - value > 0
		operand = --
	ELSE
		operand = ++
	ENDIF
	FOR loopIndex,0,ABS(EVALUATE(evalString,index)-value)
		dummy = EVALUATE(evalString + operand,index)
	NEXT
ENDIF
RETURNF EVALUATE(evalString,index)

;evalもどき。入力文字列をSTRFORM構文として処理する。戻り値は文字列形
@EVALUATE_STR(evalString,index=-1,value=-1,totalizedValue=-1,strValue="")
#FUNCTIONS
#DIMS evalString
#DIM index
#DIM value
#DIM totalizedValue
#DIMS strValue
RETURNF STRFORM("%" + evalString + "%")

@FOR_EACH(targetArray,funcStr,answerArray)
#DIM REF targetArray
#DIM REF answerArray
#DIMS funcStr
RETURN FOR_EACH_CORE(targetArray,funcStr,answerArray)

@FOR_EACH_CORE(targetArray,funcStr,answerArray)
#FUNCTION
#DIM REF targetArray
#DIM REF answerArray
#DIMS funcStr
#DIM index
SIF VARSIZE("targetArray") > VARSIZE("answerArray")
	THROW FOR_EACH 함수의 처리 상한을 넘었습니다。

FOR index,0,VARSIZE("targetArray")
	answerArray:index = EVALUATE(funcStr,index,targetArray:index)
NEXT
RETURNF index - 1

@TOTALIZE(targetArray,funcStr,firstValue=0)
#FUNCTION
#DIM REF targetArray
#DIMS funcStr
#DIM index
#DIM totalizedValue
#DIM firstValue
totalizedValue = firstValue
FOR index,0,VARSIZE("targetArray")
	totalizedValue = EVALUATE(funcStr,index,targetArray:index,totalizedValue)
NEXT
RETURNF totalizedValue


code:
;上限と下限のみのシンプルなパターン
@DISPLAY_FALLEN_PARTS(targetChara, ruleType = "", ruleName = "", minRuleValue = __INT_MIN__, maxRuleValue = __INT_MIN__,isReverseDisp = 0,katahaBit = 2)
#DIM targetChara
#DIMS ruleType
#DIMS ruleName
#DIM minRuleValue
#DIM maxRuleValue
#DIM isReverseDisp
#DIM katahaBit
#DIMS ruleText
#DIMS displayText
ruleText=%ruleType%:%TOSTR(targetChara)%:%ruleName%
displayText=%ruleName%
CALL DISPLAY_FALLEN_PARTS_CORE(displayText,ruleText,targetChara,minRuleValue,maxRuleValue,isReverseDisp,katahaBit)
RETURN

;複雑な条件がある場合のパターン。この場合出力テキストの自動生成は数値部分しか行わないので、呼び元で作る。
;katahaBit:0 MINより大きくMAX未満、1 MINより大きくMAX以下、2 MIN以上MAX未満(デフォルト)、3 MIN以上MAX以下。
@DISPLAY_FALLEN_PARTS_CORE(displayText,ruleText = "",targetChara,minRuleValue = __INT_MIN__ ,maxRuleValue = __INT_MIN__,isReverseDisp = 0,katahaBit = 2)
#DIM targetChara
#DIMS displayText
#DIMS ruleText
#DIMS printText
#DIM minRuleValue
#DIM maxRuleValue
#DIM isReverseDisp
#DIM katahaBit
#DIM calcResult
#DIMS minText
#DIMS maxText
calcResult = EVALUATE(ruleText,targetChara)
RESETCOLOR
minText = \@ GETBIT(katahaBit,1) ? 이상 # 초과 \@
SIF !GETBIT(katahaBit,1)
	minText += \@ maxRuleValue == __INT_MIN__ ? い # く \@
maxText = \@ GETBIT(katahaBit,0) ? 이하 # 미만 \@

SIF (minRuleValue != __INT_MIN__ && ((calcResult < minRuleValue) || (!GETBIT(katahaBit,1) && calcResult == minRuleValue)) && !isReverseDisp) || (maxRuleValue != __INT_MIN__ && ((calcResult > maxRuleValue) || (!GETBIT(katahaBit,0) && calcResult == maxRuleValue)) && isReverseDisp)
	SETCOLOR 0x666666
SIF (maxRuleValue != __INT_MIN__ && ((calcResult > maxRuleValue) || (!GETBIT(katahaBit,0) && calcResult == maxRuleValue)) && !isReverseDisp) || (minRuleValue != __INT_MIN__ && ((calcResult < minRuleValue) || (!GETBIT(katahaBit,1) && calcResult == minRuleValue)) && isReverseDisp)
	SETCOLOR 0xCC0000
printText =
IF minRuleValue != __INT_MIN__ && maxRuleValue != __INT_MIN__ && isReverseDisp
	THROW 범위 역전 플래그가 ON인 경우 상한과 하한 모두를 설정할 수는 없습니다 : {minRuleValue},{maxRuleValue}
ELSEIF minRuleValue != __INT_MIN__ && maxRuleValue != __INT_MIN__ && !isReverseDisp
	printText = %displayText%{minRuleValue}%minText%{maxRuleValue}%maxText%
ELSEIF minRuleValue == 1 && !isReverseDisp
	printText = %displayText%
ELSEIF maxRuleValue == 0 && isReverseDisp
	printText = %displayText%{maxRuleValue}
ELSEIF minRuleValue != __INT_MIN__
	SIF GETBIT(katahaBit,1)
		minText=
	printText = %displayText%{minRuleValue}%minText%
ELSEIF maxRuleValue != __INT_MIN__
	printText = %displayText%{maxRuleValue}%maxText%
ELSE
	THROW 상한과 하한 중 하나는 설정이 필요합니다
ENDIF
PRINTFORM %printText%
RESETCOLOR
RETURN

@DISPLAY_FALLEN_PARTS_FAILED(printText)
#DIMS printText
SETCOLOR 0xCC0000
PRINTFORM %printText%
RESETCOLOR

@SHOW_TALENT_EFFECT(typeName,targetChara,typeKey,borderValue=0,multipleValue,targetJuelNames="ALL")
#DIMS typeName
#DIM targetChara
#DIMS typeKey
#DIM borderValue
#DIM multipleValue ;10倍した値をセットする
#DIMS targetJuelNames
IF EVALUATE(typeName + ":" + TOSTR(targetChara) + ":" + typeKey) > borderValue
	SETCOLOR 0,255,255
	PRINTFORML [%typeKey%]×{(multipleValue / 10)}.{ABS(multipleValue) % 10}（%targetJuelNames%）
	RESETCOLOR
ENDIF