code:
;-------------------------------------------------
; クエストで汎用可能なコモンイベント集
; チェスト系イベント
;-------------------------------------------------
;-------------------------------------------------
; チェストが未生成の場合に引数に応じたランダムなチェストを生成する(0~9)
; 引数の値に応じて重み付け抽選
;-------------------------------------------------
@QST_CEV_CREATE_RANDOM_CHEST(ARG:0 = 100, ARG:1 = 0,  ARG:2 = 0, ARG:3 = 0, ARG:4 = 0, ARG:5 = 0, ARG:6 = 0, ARG:7 = 0, ARG:8 = 0, ARG:9 = 0)
#DIM DYNAMIC CHEST_TYPE
CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "CHEST_TYPE")
IF RESULT == -1
    CALL RAND_WT_INIT
    FOR LOCAL, 0, 10
        SIF ARG:LOCAL == 0
            CONTINUE
        CALL RAND_WT_SET(LOCAL, ARG:LOCAL)
    NEXT
    CHEST_TYPE = RAND_WT_RESULT()
    CALL QST_SET_EVENT_LIST(QST_NOWEV_LIST_IDX, "CHEST_TYPE", TOSTR(CHEST_TYPE))
    RETURN CHEST_TYPE
ELSE
    RETURN RESULT
ENDIF
;-------------------------------------------------
; 通常のチェストのコモンイベント
;-------------------------------------------------
@QST_CEV_CHEST(_LIST_REWARD)
#DIMS _LIST_REWARD
#DIMS EVENT_NAME

CALL PRINT_TITLE(EVENT_NAME)
CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_SLOT_NAME")
EVENT_NAME = %RESULTS%

PRINTFORML %QST_LEADER_NAME()%は%EVENT_NAME%の前に立った。特段施錠はされておらず、罠もないようだ
PRINTFORMW %ANAME(QST_RANDCHARA())%は中身を開放した……
IF _LIST_REWARD != ""
    CALL QST_CHANGE_ITEM(_LIST_REWARD)
ENDIF
CALL QST_DEACTIVATE_THIS_EVENT()
RETURN 1

;-------------------------------------------------
; 鍵付きチェストのコモンイベント
;-------------------------------------------------
@QST_CEV_LOCKED_CHEST(_LIST_REWARD, DIFFICULTY_RATE = 100, TRAP_RATE = 0, TRAP_PATTERN = "")
#DIMS _LIST_REWARD
#DIM  DIFFICULTY_RATE
#DIM  TRAP_RATE
#DIMS TRAP_PATTERN
#DIMS _LIST_MESSAGE
#DIMS _LIST_JUDGE_VALUE
#DIMS _LIST_DIFFICULTY
#DIMS EVENT_NAME
#DIM  DYNAMIC TARGET_ID
#DIMS DYNAMIC TRAP_TYPE
#DIM  DYNAMIC HAS_TRAP_FOUND
#DIMS DYNAMIC TRAP_NAME
#DIM  DYNAMIC EVENT_FLAG

CALL PRINT_TITLE(EVENT_NAME)
CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_SLOT_NAME")
EVENT_NAME = %RESULTS%

;解錠前の描写
CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "TRAP")
HAS_TRAP_FOUND = RESULT
TRAP_NAME = %RESULTS%
IF HAS_TRAP_FOUND == -1
    PRINTFORML %QST_LEADER_NAME()%は%EVENT_NAME%の前に立った。どうやら鍵がかかっているようだ
    PRINTFORML 開けることができれば何か役に立つものが見つかるかもしれない
    PRINTL
    SELECTCASE TRAP_PATTERN
        CASE "LEWD"
            WAIT
            CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%QST_LEADER_NAME()%は%EVENT_NAME%の表面で奇怪な淫紋が明滅するのを目にした@/C@", 1)
            WAIT
            PRINTL
        CASEELSE
    ENDSELECT
ELSE
    PRINTFORML %QST_LEADER_NAME()%は%EVENT_NAME%の前に立った
    IF TRAP_NAME != "なし"
        CALLF TAG_PRINT(@"これには@C:{カラー_注意}@%RESULTS%@/C@の罠が仕掛けられていることが判明している", 1)
    ELSE
        PRINTFORML これには特に罠は仕掛けられていないことが判明している
    ENDIF
    PRINTL
ENDIF

$INPUT_LOOP
PRINTL
PRINTFORML ……さて、どうすべきだろうか？
PRINTL

_LIST_MESSAGE '= "解錠を試みる(器用),力づくでこじ開ける(身体),"
_LIST_JUDGE_VALUE '= "器用,身体,"
_LIST_DIFFICULTY '= @"%TOSTR(DIFFICULTY_RATE)%,%TOSTR((DIFFICULTY_RATE * 150) / 100)%,"

;トラップ未判定の場合は観察判定を追加
IF HAS_TRAP_FOUND == -1 && TRAP_NAME != "なし"
    _LIST_MESSAGE = %LIST_ADD(_LIST_MESSAGE, "罠の有無を調べる(観察)")%
    _LIST_JUDGE_VALUE = %LIST_ADD(_LIST_JUDGE_VALUE, "観察")%
    _LIST_DIFFICULTY = %LIST_ADD(_LIST_DIFFICULTY, @"%TOSTR(DIFFICULTY_RATE)%")%
ENDIF

CALL QST_ROLL_MULTI(_LIST_JUDGE_VALUE, _LIST_MESSAGE, _LIST_DIFFICULTY,,,,, 1, "何も考えず開ける(確定失敗)")
TARGET_ID = RESULT:1
IF RESULT == 1
    IF RESULTS != "観察"
        PRINTFORMW %ANAME(TARGET_ID)%は%EVENT_NAME%の解錠に成功した！
        CALL QST_CHANGE_ITEM(_LIST_REWARD)
        CALL QST_DEACTIVATE_THIS_EVENT()
        RETURN 1
    ELSE
        ;観察判定は解錠はしない
        CALL QST_CEV_GET_TRAP_PATTERN_PRESET(TRAP_PATTERN)
        TRAP_TYPE = %RESULTS%
        CALL QST_SET_EVENT_LIST(QST_NOWEV_LIST_IDX, "TRAP", TRAP_TYPE)
        IF  TRAP_TYPE != "なし"
            PRINTFORML %ANAME(TARGET_ID)%は%EVENT_NAME%の罠を見抜いた
            PRINTL
            CALLF TAG_PRINT(@"どうやら@C:{カラー_注意}@%TRAP_TYPE%@/C@の罠が仕掛けられているようだ……", 1)
            WAIT
        ELSE
            PRINTFORML %ANAME(TARGET_ID)%は%EVENT_NAME%に何も罠が無い事を確認した
        ENDIF
        GOTO INPUT_LOOP
    ENDIF
ELSEIF !RESULT
    IF RESULTS != "観察"
        PRINTFORMW %ANAME(TARGET_ID)%は%EVENT_NAME%の解錠に失敗した……
        PRINTL
        ;罠が生成されていない場合は生成する。生成済みの場合は確定でその罠を発動する
        CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "TRAP")
        IF RESULT != -1
            CALL QST_CEV_TRAP_EVENT(TARGET_ID, RESULTS)
        ELSE
            IF RAND:100 < TRAP_RATE
                CALL QST_CEV_GET_TRAP_PATTERN_PRESET(TRAP_PATTERN)
                TRAP_TYPE = %RESULTS%
                CALL QST_SET_EVENT_LIST(QST_NOWEV_LIST_IDX, "TRAP", TRAP_TYPE)
                CALL QST_CEV_TRAP_EVENT(RESULT:1, TRAP_TYPE)
            ENDIF
        ENDIF
        ;解錠手段が残っている場合は入力ループに戻る
        ;ウフフフラグが立っている場合は入力ループを離脱
        CALL QST_GET_EVENT_FLAG_BY_IDX()
        EVENT_FLAG = RESULT
        SIF !(GETBIT(EVENT_FLAG, 1) && GETBIT(EVENT_FLAG, 2)) && !FLAG:ウフフフラグ
            GOTO INPUT_LOOP
    ELSE
        PRINTFORMW %ANAME(TARGET_ID)%は%EVENT_NAME%を調べて見たものの、何もわからなかったようだ……
        GOTO INPUT_LOOP
    ENDIF
ENDIF
;-------------------------------------------------
; 宝箱のトラップパターン
;-------------------------------------------------
@QST_CEV_GET_TRAP_PATTERN_PRESET(TRAP_PATTERN)
#DIMS TRAP_PATTERN
#DIMS TRAP_TYPE
SELECTCASE TRAP_PATTERN
    CASE "", "COMMON"
        CALL RAND_WT_INIT()
        CALL RAND_WT_SET(0, 40)
        CALL RAND_WT_SET(1, 30)
        CALL RAND_WT_SET(2, 25)
        CALL RAND_WT_SET(3, 5)
        SELECTCASE RAND_WT_RESULT()
            CASE 0
                TRAP_TYPE '= "仕込針"
            CASE 1
                TRAP_TYPE '= "催淫ガス"
            CASE 2
                TRAP_TYPE '= "腐食液"
            CASE 3
                TRAP_TYPE '= "なし"
        ENDSELECT
    CASE "LEWD", "LEWD_LV2"
        CALL RAND_WT_INIT()
        CALL RAND_WT_SET(0, 10)
        CALL RAND_WT_SET(1, 10)
        CALL RAND_WT_SET(2, 10)
        CALL RAND_WT_SET(3, 10)
        IF TRAP_PATTERN == "LEWD_LV2"
            CALL RAND_WT_SET(4, 25)
            CALL RAND_WT_SET(5, 15)
        ENDIF
        SELECTCASE RAND_WT_RESULT()
            CASE 0
                TRAP_TYPE '= "催淫ガス"
            CASE 1
                TRAP_TYPE '= "腐食液"
            CASE 2
                TRAP_TYPE '= "ブラシ触手"
            CASE 3
                TRAP_TYPE '= "Ｃコイン"
            CASE 4
                TRAP_TYPE '= "触手"
            CASE 5
                TRAP_TYPE '= "フェイスハガー"
        ENDSELECT
ENDSELECT
RESULTS = %TRAP_TYPE%

;-------------------------------------------------
; 罠イベント
;-------------------------------------------------
@QST_CEV_TRAP_EVENT(TARGET_ID, TRAP_TYPE)
#DIM  TARGET_ID
#DIMS TRAP_TYPE
#DIM  DYNAMIC MOB_ID

SIF LIST_COUNT(TRAP_TYPE) > 0
    TRAP_TYPE = %LIST_RAND(TRAP_TYPE)%

SELECTCASE TRAP_TYPE
    CASE "仕込針"
        CALL PRINT_TITLE(@"仕込針の罠", "トラップ")
        CALLF TAG_PRINT(@"飛び出した針が%ANAME(TARGET_ID)%を襲う！", 1)
        CALL QST_CHANGE_HP(TARGET_ID, -200)
        WAIT
        RETURN 1
    CASE "催淫ガス"
        CALL PRINT_TITLE(@"催淫ガスの罠", "エロトラップ")
        CALLF TAG_PRINT(@"桃色の霧が%ANAME(TARGET_ID)%の正常な判断力を奪う……", 1)
        CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%ANAME(TARGET_ID)%は発情してしまったようだ……@/C@", 1)
        TCVAR:(TARGET_ID):媚薬 += 1
        WAIT
        RETURN 1
    CASE "腐食液"
        CALL PRINT_TITLE(@"腐食液の罠", "エロトラップ")
        CALLF TAG_PRINT(@"噴出した腐臭を放つ液体が%ANAME(TARGET_ID)%を襲う！", 1)
        IF RAND:2
            CALL QST_ARMOR_BREAK(TARGET_ID, 被覆部位_乳首, 100)
        ELSE
            CALL QST_ARMOR_BREAK(TARGET_ID, 被覆部位_秘部, 100)
        ENDIF
        IF !RESULT
            PRINTFORMW %ANAME(TARGET_ID)%に液体が付着したものの幸い何も起きなかったようだ……
        ENDIF
        WAIT
        RETURN 1
    CASE "ブラシ触手", "触手", "フェイスハガー"
        ;調教イベントの初期設定
        CALL CLEAR_MPLY()
        CALL CLEAR_MTAR()
        FLAG:ウフフフラグ = 1
        FLAG:調教モード = 調教_慰安
        CVARSET CFLAG, GETNUM(CFLAG, "調教参加フラグ") , 0
        CFLAG:TARGET_ID:主導除外 = 1
        CFLAG:TARGET_ID:凌辱被害者フラグ = 1
        CFLAG:TARGET_ID:調教参加フラグ = 1
        SELECTCASE TRAP_TYPE
            CASE "ブラシ触手"
                CALL PRINT_TITLE(@"ブラシ触手の罠", "エロトラップ")
                CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%ANAME(TARGET_ID)%は飛び出してきた無数の突起を持つ触手にたちまち絡め取られてしまった……@/C@", 1)
                WAIT
                TFLAG:調教ターン数 = RAND(5, 7)
                FOR LOCAL, 0, RAND(3, 6)
                    CALL QST_TRAIN_MOB_PRESET("ブラシ触手")
                    MOB_ID = RESULT
                    ;生成した触手モブを触手召喚状態にする
                    CALL ADD_MPLY(MOB_ID)
                    CALL SET_EQUIP(GETNUM(TRAINNAME, "触手召喚"), 1)
                    CALL DEL_MPLY(MOB_ID)
                NEXT
            CASE "フェイスハガー"
                CALL PRINT_TITLE(@"フェイスハガーの罠", "エロトラップ")
                CALLF TAG_PRINT(@"@C:{カラー_ピンク}@突然飛び出してきた肉腫が%ANAME(TARGET_ID)%の顔面にガッチリと張り付いた……！@/C@", 1)
                WAIT
                TFLAG:調教ターン数 = RAND(5, 7)
                FOR LOCAL, 0, 1
                    CALL QST_TRAIN_MOB_PRESET("フェイスハガー")
                    MOB_ID = RESULT
                    ;生成した触手モブを触手召喚状態にする
                    CALL ADD_MPLY(MOB_ID)
                    CALL SET_EQUIP(GETNUM(TRAINNAME, "触手召喚"), 1)
                    CALL DEL_MPLY(MOB_ID)
                NEXT
            CASEELSE
                CALL PRINT_TITLE(@"触手の罠", "エロトラップ")
                CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%ANAME(TARGET_ID)%は飛び出してきた無数の触手にたちまち絡め取られてしまった……@/C@", 1)
                WAIT
                TFLAG:調教ターン数 = RAND(8, 10)
                FOR LOCAL, 0, RAND(3, 6)
                    CALL QST_TRAIN_MOB_PRESET("触手")
                    MOB_ID = RESULT
                    ;生成した触手モブを触手召喚状態にする
                    CALL ADD_MPLY(MOB_ID)
                    CALL SET_EQUIP(GETNUM(TRAINNAME, "触手召喚"), 1)
                    CALL DEL_MPLY(MOB_ID)
                NEXT
        ENDSELECT
        ;慰安モブは調教終了後に削除されてしまうため、名前などの情報を連想配列に退避
        MAP_CREATE "TRAP_EVENT_TRAIN"
        MAP_SET "TRAP_EVENT_TRAIN", "MOB_NAME", "触手"
        MAP_SET "TRAP_EVENT_TRAIN", "TARGET_NAME", ANAME(TARGET_ID)
        CALL QST_ENQUEUE_TRAIN_EXIT_FUNC("QST_CEV_TRAP_EVENT_TRAIN_END")
        RETURN 1
    CASE "Ｃコイン"
        CALL PRINT_TITLE(@"クリーピングコインの罠", "エロトラップ")
        CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%ANAME(TARGET_ID)%は飛び出してきた無数の動き回るコインに足をとられ、転んでしまった……@/C@", 1)
        WAIT
        ;調教イベントの初期設定
        CALL CLEAR_MPLY()
        CALL CLEAR_MTAR()
        FLAG:ウフフフラグ = 1
        FLAG:調教モード = 調教_慰安
        TFLAG:調教ターン数 = RAND(5, 7)
        CVARSET CFLAG, GETNUM(CFLAG, "調教参加フラグ") , 0
        CFLAG:TARGET_ID:主導除外 = 1
        CFLAG:TARGET_ID:凌辱被害者フラグ = 1
        CFLAG:TARGET_ID:調教参加フラグ = 1
        FOR LOCAL, 0, 3
            CALL QST_TRAIN_MOB_PRESET("Ｃコイン")
        NEXT
        ;慰安モブは調教終了後に削除されてしまうため、名前などの情報を連想配列に退避
        MAP_CREATE "TRAP_EVENT_TRAIN"
        MAP_SET "TRAP_EVENT_TRAIN", "MOB_NAME", "クリーピングコイン"
        MAP_SET "TRAP_EVENT_TRAIN", "TARGET_NAME", ANAME(TARGET_ID)
        CALL QST_ENQUEUE_TRAIN_EXIT_FUNC("QST_CEV_TRAP_EVENT_TRAIN_END")
        RETURN 1
ENDSELECT
RETURN 0

@QST_CEV_TRAP_EVENT_TRAIN_END
#DIMS TARGET_NAME
#DIMS MOB_NAME

TARGET_NAME = %MAP_GET("TRAP_EVENT_TRAIN", "TARGET_NAME")%
MOB_NAME = %MAP_GET("TRAP_EVENT_TRAIN", "MOB_NAME")%

CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%TARGET_NAME%は%MOB_NAME%による執拗な辱めからようやく解放された……@/C@", 1)
WAIT
;KOJO_EVENT候補

MAP_RELEASE "TRAP_EVENT_TRAIN"


code:
;-------------------------------------------------
; クエストで汎用可能なコモンイベント集
; 戦闘系イベント
;-------------------------------------------------
;-------------------------------------------------
; 汎用戦闘イベント
;-------------------------------------------------
@QST_CEV_COMBAT(PRESET_NAME)
#DIMS PRESET_NAME
#DIM  DYNAMIC GROUP_SIZE
#DIMS DYNAMIC _LIST_REWARD

;白兵戦参加メンバーの初期化
CALL CC_INIT()
;クエストのパーティメンバー全員を攻撃側として戦闘メンバーに追加
CALL CC_ADDPARTY()
CALL QST_CEV_COMBAT_MOB_PRESET(PRESET_NAME)
CALL CLOSE_COMBAT()
PRINTL
IF RESULT == 1
    CALL CC_APPLY_CHARA_HP()
    CALL CC_GET_LOOT_FROM("DEFENDER")
    CALL PRINT_NOTICE(@"%QST_LEADER_NAME()%は戦闘に勝利した！")
    WAIT
    RETURN 1
ELSE
    CALL CC_APPLY_CHARA_HP()
    CALL PRINT_NOTICE(@"%QST_LEADER_NAME()%は戦闘に敗北してしまった……")
    WAIT
    RETURN 0
ENDIF

@QST_CEV_COMBAT_MOB_PRESET(PRESET_NAME)
#DIMS PRESET_NAME
#DIMS DYNAMIC _LIST_REWARD
#DIM  DYNAMIC GROUP_SIZE
SELECTCASE PRESET_NAME
    CASE "ゴブリン"
        GROUP_SIZE = RAND(3, 4)
        FOR LOCAL, 0, GROUP_SIZE
            CALL CC_ADDMOB_FROM_TABLE("DEFENDER", "ゴブリン", @"ゴブリン%TOFULL(TOSTR(LOCAL + 1))%")
        NEXT
    CASEELSE
        TRYCCALLFORM QST_COMBAT_ENEMY_PARTY_%PRESET_NAME%
        CATCH
            PRINTFORML 指定されたプリセット名 %PRESET_NAME%
            THROW エラー:@QST_CEV_COMBAT_MOB_PRESET　指定されたプリセットに対応するエネミーパーティ定義関数が存在しません
        ENDCATCH

ENDSELECT

repo_name: pervysquirrelz/erafl

license: unknown


code:
;-------------------------------------------------
; クエストで汎用可能なコモンイベント集
; 疑似設備系イベント
;-------------------------------------------------
; DIC_OPTION のパラメータ一覧
; MODULE_ID: 擬似設備として使う設備番号(HOUSING_MODULE_DATA.ERB参照)
; PAUSE_BGM: 1 = BGM停止
; ALLOW_COM: 1 = 通常コマンドを許可
; ALLOW_UFUFUCOM: 1 = ウフフ系コマンドを許可
; MODULE_NAME: 未使用時の設備の表示名
; USE_MODULE_MESSAGE: 設備を使用した際のメッセージ
; MODULE_NAME_AT_USING: 使用時の設備の表示名
; STOP_USE_MODULE_MESSAGE: 設備使用を止めた際のメッセージ
; REDRESS_AT_STOP: 1 = 使用停止時に着衣を元に戻す
; ALLOW_OTHER_EVENT: 1 = 他のイベントの実行を許可
;-------------------------------------------------
@QST_CEV_USE_DUMMY_MODULE(DIC_OPTION)
#DIMS DIC_OPTION
#DIM  DYNAMIC IS_ACTIVE
#DIM  DYNAMIC DUMMY_MODULE_ID
#DIM  DYNAMIC CHARA_ID

CALL QST_GET_EVENT_FLAG(QST_NOWEV)
IS_ACTIVE = RESULT

;ダミーモジュール使用に関するオプション初期化
TFLAG:クエスト_ダミー設備ID = 0
FLAG:クエスト_交流コマンド許可 = 0
FLAG:クエスト_ウフフ許可 = 0
FLAG:移動制限フラグ = 0
QST_イベント選択制限 = -1

;既に使用中なら使用状態を解除
IF IS_ACTIVE
    ;イベント名称を元に戻す
    CALL QST_SET_EVENT_FLAG(QST_NOWEV, 0)
    IF DIC_CONTAINSKEY(DIC_OPTION, "MODULE_NAME")
        CALL QST_SET_EVENT_SLOT_NAME(QST_NOWEV, DIC_GET(DIC_OPTION, "MODULE_NAME"))
    ENDIF
    ;着衣を元に戻す
    IF DIC_CONTAINSKEY(DIC_OPTION, "REDRESS_AT_STOP")
        CALL QST_REDRESSALL()
    ENDIF
    ;使用中止メッセージ
    IF DIC_CONTAINSKEY(DIC_OPTION, "STOP_USE_MODULE_MESSAGE")
        PRINTFORMW %DIC_GET(DIC_OPTION, "STOP_USE_MODULE_MESSAGE")%
    ENDIF
    ;BGMを停止していた場合は再生
    IF TOINT(DIC_GET(DIC_OPTION, "PAUSE_BGM")) == 1
        CALL FL_REPLAYBGM()
    ENDIF

    FOR CHARA_ID, 0, CHARANUM
        ;コマンド継続状況を解除
        IF IS_PARTICIPATE_TRAIN(CHARA_ID)
            ;EQUIP解除
            CALL RELEASE_ALL_EQUIP(CHARA_ID, 1)
        ENDIF
    NEXT
    RETURN
ENDIF

;擬似モジュール使用時のフラグ操作
CALL QST_SET_EVENT_FLAG(QST_NOWEV, 1)
;このイベントIDのイベント以外実行不可に
QST_イベント選択制限 = QST_NOWEV
;1=隣接エリアのみ移動可,2=エリア移動不可
FLAG:移動制限フラグ = 2
;交流系コマンドの実行を許可
FLAG:クエスト_交流コマンド許可 = 1

;オプションの適用
;擬似モジュールIDのセット
IF DIC_CONTAINSKEY(DIC_OPTION, "MODULE_ID")
    TFLAG:クエスト_ダミー設備ID = TOINT(DIC_GET(DIC_OPTION, "MODULE_ID"))
ENDIF

;擬似モジュールを使用中の名称に変更
IF DIC_CONTAINSKEY(DIC_OPTION, "MODULE_NAME_AT_USING")
    CALL QST_SET_EVENT_SLOT_NAME(QST_NOWEV, DIC_GET(DIC_OPTION, "MODULE_NAME_AT_USING"))
ENDIF
;通常の交流コマンドの実行可否
IF TOINT(DIC_GET(DIC_OPTION, "ALLOW_COM")) == 1
    FLAG:クエスト_交流コマンド許可 = 1
ENDIF
;ウフフ系コマンドの実行可否
IF TOINT(DIC_GET(DIC_OPTION, "ALLOW_UFUFUCOM")) == 1
    FLAG:クエスト_ウフフ許可 = 1
ENDIF
;他のイベントの実行可否
IF TOINT(DIC_GET(DIC_OPTION, "ALLOW_OTHER_EVENT")) == 1
    QST_イベント選択制限 = -1
ENDIF
;使用メッセージの表示
IF DIC_CONTAINSKEY(DIC_OPTION, "USE_MODULE_MESSAGE")
    PRINTFORMW %DIC_GET(DIC_OPTION, "USE_MODULE_MESSAGE")%
ENDIF
;BGMの再生停止
IF TOINT(DIC_GET(DIC_OPTION, "PAUSE_BGM")) == 1
    CALL FL_PAUSEBGM()
ENDIF


code:
;-------------------------------------------------
; クエストで汎用可能なコモンイベント集
; 抽選系イベント
;-------------------------------------------------
;-------------------------------------------------
; 衣服の脱着
;-------------------------------------------------
@QST_REDRESS(CHARA_ID, SHOW_MESSAGE = 1)
#DIM CHARA_ID
#DIM SHOW_MESSAGE

CALL HO_REDRESS(CHARA_ID)
IF RESULT
    SIF SHOW_MESSAGE
        PRINTFORMW %ANAME(CHARA_ID)%は%SPLIT_RAND("衣服の乱れ/着衣の乱れ/身だしなみ",1)%をそっと整えた……
    RETURN RESULT
ENDIF

@QST_REDRESSALL(SHOW_MESSAGE = 1)
#DIM CHARA_ID
#DIM SHOW_MESSAGE
#DIM DYNAMIC REDRESS_CHARANUM
#DIM DYNAMIC SHOW_NAME_CHARA

FOR LOCAL, 0, LIST_COUNT(_LIST_QST_PARTY)
    CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, LOCAL))
    CALL QST_REDRESS(CHARA_ID, 0)
    IF RESULT
        REDRESS_CHARANUM ++
        SHOW_NAME_CHARA = CHARA_ID
    ENDIF
NEXT
IF REDRESS_CHARANUM > 0 && SHOW_MESSAGE
    PRINTFORMW %ANAME(SHOW_NAME_CHARA, REDRESS_CHARANUM)%は%SPLIT_RAND("衣服の乱れ/着衣の乱れ/身だしなみ",1)%をそっと整えた……
ENDIF
RETURN REDRESS_CHARANUM

;-------------------------------------------------
; エリア効果
;-------------------------------------------------
;指定地点にエリア効果を発生させる
@QST_SET_ROOM_EFFECT(EFFECT_NAME, VALUES, ROOM_IDX = -1)
#DIMS EFFECT_NAME
#DIMS VALUES
#DIM  ROOM_IDX
#DIMS DYNAMIC ROOM_EFFECT_MAP

IF ROOM_IDX == -1
    ROOM_IDX = HO_MASTER現在地
ENDIF
ROOM_EFFECT_MAP '= @"MAP_{ROOM_IDX}_ROOM_EFFECT"

IF !MAP_HAS(ROOM_EFFECT_MAP, EFFECT_NAME) > 0
    MAP_SET ROOM_EFFECT_MAP, EFFECT_NAME, VALUES
    DEBUGPRINTFORML ROOM_EFFECT_MAP = %ROOM_EFFECT_MAP%, EFFECT_NAME = %EFFECT_NAME%, RESULT = {RESULT}
ENDIF

;指定地点のエリア効果を削除
@QST_REMOVE_ROOM_EFFECT(EFFECT_NAME, ROOM_IDX = -1)
#DIMS EFFECT_NAME
#DIM  ROOM_IDX
#DIMS DYNAMIC ROOM_EFFECT_MAP

IF ROOM_IDX == -1
    ROOM_IDX = HO_MASTER現在地
ENDIF
ROOM_EFFECT_MAP '= @"MAP_{ROOM_IDX}_ROOM_EFFECT"
MAP_REMOVE ROOM_EFFECT_MAP, EFFECT_NAME


code:
;-------------------------------------------------
;;; クエストで汎用可能なコモンイベント集
;;; その他イベント
;;; - ARG
;;; _LIST_JUDGE_VALUE (str(list))判定値リスト
;;; _LIST_MESSAGE (str(list))ボタンテキストリスト
;;; _LIST_DIFFICULTY (str(list))難易度リスト
;;; EXP_GAIN (int)経験値獲得量
;;; ALLOW_CANCEL (int(bool))キャンセルを許可するか
;;; CANCEL_MESSAGE (str)キャンセルボタンのテキスト
;;; TARGET_CHARA_ID (int)キャラを明示的に指定する場合、そのキャラID。未指定でパーティメンバから選択
;;; ALLOW_SUICIDE (int(bool))自滅を許可するか
;;; SUICIDE_MESSAGE (str)自滅ボタンのテキスト
;;; ALLOW_RETRY (int(bool))失敗選択肢の再挑戦を許可するか
;;; - RESULT
;;;   - RESULT:0 判定結果: 0=失敗, 1=成功, -1=キャンセル
;;;   - RESULT:1 挑戦したキャラのID
;;;   - RESULT:2 選択肢番号(0～)
;-------------------------------------------------
@QST_ROLL_MULTI(_LIST_JUDGE_VALUE, _LIST_MESSAGE, _LIST_DIFFICULTY, EXP_GAIN = 3, ALLOW_CANCEL = 1, CANCEL_MESSAGE = "何もしない", TARGET_CHARA_ID = -1, ALLOW_SUICIDE = 0, SUICIDE_MESSAGE = "わざと失敗する", ALLOW_RETRY = 0)
#DIMS _LIST_MESSAGE
#DIMS _LIST_JUDGE_VALUE
#DIMS _LIST_DIFFICULTY
#DIM  EXP_GAIN
#DIM  ALLOW_CANCEL
#DIMS CANCEL_MESSAGE
#DIM  TARGET_CHARA_ID
#DIM  REDRAW_MODE
#DIM  ALLOW_SUICIDE
#DIMS SUICIDE_MESSAGE
#DIM  ALLOW_RETRY
#DIMS DYNAMIC JUDGE_TYPE
#DIM  DYNAMIC IS_JUDGED
#DIM  DYNAMIC INPUT_VALUE
#DIM  DYNAMIC EVENT_FLAG
#DIM  DYNAMIC ROLL_RESULT
#DIM  DYNAMIC CHALLENGED_CHARA
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC FIRST_LINE

#DIM CONST COUNT_BIAS = 10000 ; 他の選択肢に被らない値にする為の下駄
#DIM  DYNAMIC MAX_MASSAGE_LEN
#DIM  DYNAMIC MAX_NAME_LEN
#DIM  DYNAMIC MAX_RATE_LEN, 2
#DIMS STR_SPACER

#DIM  DYNAMIC BUTTON_NO
#DIMS DYNAMIC BUTTON_TEXT
#DIMS DYNAMIC SELECT_TEXT
#DIM  DYNAMIC DIFFICULTY
#DIM  DYNAMIC SUCCESS_RATE
#DIM  DYNAMIC SELECT_ROW
#DIM  DYNAMIC SELECT_COL
#DIM  DYNAMIC BEST_ROLL_ALL_MASTER

CURRENTREDRAW
REDRAW_MODE = RESULT
REDRAW 0
VARSET RESULTS
FIRST_LINE = LINECOUNT

;事前処理
;・表示位置調整用に各種表示文字列のなかで一番長い長さを取得
;・最良選出がすべてあなたになるかを判定
MAX_RATE_LEN:0 = 2
MAX_RATE_LEN:1 = 2
BEST_ROLL_ALL_MASTER = 1
FOR LOCAL, 0, LIST_COUNT(_LIST_MESSAGE)
    ;メッセージ
    IF MAX_MASSAGE_LEN < STRLENS(LIST_GET(_LIST_MESSAGE, LOCAL))
        MAX_MASSAGE_LEN = STRLENS(LIST_GET(_LIST_MESSAGE, LOCAL))
    ENDIF
    ;最良選出キャラの名前と成功率
    DIFFICULTY   = TOINT(LIST_GET(_LIST_DIFFICULTY, LOCAL))
    JUDGE_TYPE  '= LIST_GET(_LIST_JUDGE_VALUE, LOCAL)
    CHARA_ID     = BEST_ROLL_CHARA_CHOICE_PARTY(GETNUM(ABL, JUDGE_TYPE))
    SUCCESS_RATE = QST_GET_ROLL_SUCCESS_RATE(ABL:CHARA_ID:JUDGE_TYPE, DIFFICULTY)
    IF MAX_NAME_LEN < STRLENS(ANAME(CHARA_ID))
        MAX_NAME_LEN = STRLENS(ANAME(CHARA_ID))
    ENDIF
    ;成功率が100.0%以上の場合は3桁表示
    SIF SUCCESS_RATE >= 1000
        MAX_RATE_LEN:0 = 3
    ;成功率が100.0%以上の場合は3桁表示
    SIF SUCCESS_RATE >= 1000 && CHARA_ID == MASTER
        MAX_RATE_LEN:1 = 3
    ;最良選出キャラがマスターでない
    SIF CHARA_ID != MASTER
        BEST_ROLL_ALL_MASTER = 0
NEXT
;キャンセルメッセージとの比較
IF MAX_MASSAGE_LEN < STRLENS(CANCEL_MESSAGE)
    MAX_MASSAGE_LEN = STRLENS(CANCEL_MESSAGE)
ENDIF
;自滅用メッセージとの比較
IF MAX_MASSAGE_LEN < STRLENS(SUICIDE_MESSAGE)
    MAX_MASSAGE_LEN = STRLENS(SUICIDE_MESSAGE)
ENDIF

$ASK_LOOP
; 渡された選択肢の表示処理(失敗済みの選択肢は選択不可) ボタンの値は(FOR文で増えていく)LOCALの値
FOR LOCAL, 0, LIST_COUNT(_LIST_MESSAGE)
    ;CALL QST_GET_EVENT_FLAG_BY_IDX()
    ;EVENT_FLAG = RESULT
    IF !ALLOW_RETRY
        EVENT_FLAG = TOINT(QST_GET_FLAGMAP(@"EVENT_{QST_NOWEV_LIST_IDX}_ROLL_RESULT"))
    ELSE
        EVENT_FLAG = 0
    ENDIF
    GETBIT EVENT_FLAG, LOCAL + 1
    IF !RESULT
        ;コマンド
        BUTTON_NO    = LOCAL
        BUTTON_TEXT '= LIST_GET(_LIST_MESSAGE, LOCAL)
        SELECT_TEXT '= @"　@B:{BUTTON_NO}@[%BUTTON_TEXT%]@/B@ "
        ; 既にロールするキャラが決まっているなら自動選出はさせない
        IF TARGET_CHARA_ID == -1
            ;位置調整用スペースの数計算
            STR_SPACER '= " " * (MAX_MASSAGE_LEN - STRLENS(LIST_GET(_LIST_MESSAGE, LOCAL)))
            SELECT_TEXT += STR_SPACER

            ;判定値の取得
            DIFFICULTY   = TOINT(LIST_GET(_LIST_DIFFICULTY, LOCAL))
            JUDGE_TYPE  '= LIST_GET(_LIST_JUDGE_VALUE, LOCAL)

            ;対象ロールの最良キャラ
            CHARA_ID     = BEST_ROLL_CHARA_CHOICE_PARTY(GETNUM(ABL, JUDGE_TYPE))
            SUCCESS_RATE = QST_GET_ROLL_SUCCESS_RATE(ABL:CHARA_ID:JUDGE_TYPE, DIFFICULTY)
            STR_SPACER  '= " " * (MAX_NAME_LEN - STRLENS(ANAME(CHARA_ID)))

            BUTTON_NO    = LOCAL + COUNT_BIAS
            BUTTON_TEXT '= @"最良選出:%ANAME(CHARA_ID)%%STR_SPACER%({MIN(100, SUCCESS_RATE / 10), MAX_RATE_LEN:0}\%)"
            SELECT_TEXT += @"@B:{BUTTON_NO}@[%BUTTON_TEXT%]@/B@"

            ;自分がやる(あなたが実行)
            ;・あなたがパーティに居る場合のみ表示
            ;・最良選出キャラがすべてあなたの場合は表示しない
            IF QST_LEADER_ID() == MASTER && !BEST_ROLL_ALL_MASTER
                SELECT_TEXT += " "
                SUCCESS_RATE = QST_GET_ROLL_SUCCESS_RATE(ABL:MASTER:JUDGE_TYPE, DIFFICULTY)

                BUTTON_NO    = LOCAL + (COUNT_BIAS * 2)
                BUTTON_TEXT '= @"自分がやる({MIN(100, SUCCESS_RATE / 10), MAX_RATE_LEN:1}\%)"
                SELECT_TEXT += @"@B:{BUTTON_NO}@[%BUTTON_TEXT%]@/B@"
            ENDIF

            ;CALLF TAG_PRINT(@"@C:{カラー_白}@@B:{LOCAL}@　[%LIST_GET(_LIST_MESSAGE, LOCAL)%]@/B@@@%STR_SPACER%@@@B:{LOCAL + COUNT_BIAS}@[最良選出:%ANAME(CHARA_ID)%]@/B@@/C@", 5)
            ;ELSE
            ;   BUTTON_TEXT '= @"@C:{カラー_白}@@B:{BUTTON_NO_COMMAND}@　[%BUTTON_TEXT_COMMAND%]@/B@@/C@"
            ;CALLF TAG_PRINT(@"@C:{カラー_白}@@B:{LOCAL}@　[%LIST_GET(_LIST_MESSAGE, LOCAL)%]@/B@@/C@", 5)
        ENDIF
        CALLF TAG_PRINT(SELECT_TEXT, 5)
    ELSE
        CALLF TAG_PRINT(@"@C:{カラー_選択不可}@　[%LIST_GET(_LIST_MESSAGE, LOCAL)%]@/C@", 1)
    ENDIF
NEXT
; 自滅用の選択肢の表示処理(失敗済みの選択肢は選択不可) ボタンの値は9998
IF ALLOW_SUICIDE
    IF !GETBIT(EVENT_FLAG, 16)
        CALLF TAG_PRINT(@"@C:{カラー_白}@@B:9998@　[%SUICIDE_MESSAGE%]@/B@@/C@", 5)
    ELSE
        CALLF TAG_PRINT(@"@C:{カラー_選択不可}@　[%SUICIDE_MESSAGE%]@/C@", 5)
    ENDIF
ENDIF
; キャンセル選択肢の表示処理 ボタンの値は9999
IF ALLOW_CANCEL
    PRINTL
    CALLF TAG_PRINT(@"@C:{カラー_白}@@B:9999@　[%CANCEL_MESSAGE%]@/B@@/C@", 5)
ENDIF

REDRAW REDRAW_MODE
ONEINPUT
INPUT_VALUE = RESULT
CLEARLINE 1

; 入力値に応じた処理 (選択肢は0番目から数えるので最大値は-1しないと渡された選択肢の範囲よりも1つ多い値でも範囲内と判定されてしまう)
IF INRANGE(INPUT_VALUE, 0, LIST_COUNT(_LIST_MESSAGE) - 1)
    ; 渡された選択肢での処理
    JUDGE_TYPE = %LIST_GET(_LIST_JUDGE_VALUE, INPUT_VALUE)%
    IF JUDGE_TYPE != "なし"
        CALL QST_PARTY_ROLL(LIST_GET(_LIST_JUDGE_VALUE, INPUT_VALUE), TOINT(LIST_GET(_LIST_DIFFICULTY, INPUT_VALUE)), 1, EXP_GAIN, , TARGET_CHARA_ID)
        ROLL_RESULT = RESULT
        CHALLENGED_CHARA = RESULT:1
        IF RESULT != -1
            SETBIT EVENT_FLAG, INPUT_VALUE + 1
            ;CALL QST_SET_EVENT_FLAG_BY_IDX(EVENT_FLAG)
            IF !ALLOW_RETRY
                CALL QST_SET_FLAGMAP(@"EVENT_{QST_NOWEV_LIST_IDX}_ROLL_RESULT", TOSTR(EVENT_FLAG))
            ENDIF
        ELSEIF RESULT == -1
            CLEARLINE LINECOUNT - FIRST_LINE
            GOTO ASK_LOOP
        ENDIF
    ENDIF
    RESULT:1 = CHALLENGED_CHARA
    RESULT:2 = INPUT_VALUE
    RESULTS = %LIST_GET(_LIST_JUDGE_VALUE, INPUT_VALUE)%
    RETURN ROLL_RESULT
ELSEIF INPUT_VALUE == 9998
    ; 自滅用の選択肢の処理
    CALL QST_SELECT_CHARA(1, "行動を実行するキャラクターを選択してください")
    SIF RESULT == -1
        RETURN -1
    RESULT:1 = RESULT
    SETBIT EVENT_FLAG, 16
    ;CALL QST_SET_EVENT_FLAG_BY_IDX(EVENT_FLAG)
    IF !ALLOW_RETRY
        CALL QST_SET_FLAGMAP(@"EVENT_{QST_NOWEV_LIST_IDX}_ROLL_RESULT", TOSTR(EVENT_FLAG))
    ENDIF
    RETURN 0
ELSEIF INPUT_VALUE == 9999
    ; キャンセル選択肢の処理
    RETURN -1
ELSEIF TARGET_CHARA_ID == -1 && (INRANGE(INPUT_VALUE - COUNT_BIAS, 0, LIST_COUNT(_LIST_MESSAGE) - 1) || INRANGE(INPUT_VALUE - (COUNT_BIAS * 2), 0, LIST_COUNT(_LIST_MESSAGE) - 1))
    ; キャラ指定ありのコマンド選択
    ;選択したボタンの行(項目)列(キャラ指定)を分解
    SELECT_ROW = INPUT_VALUE % COUNT_BIAS
    SELECT_COL = INPUT_VALUE / COUNT_BIAS
    JUDGE_TYPE = %LIST_GET(_LIST_JUDGE_VALUE, SELECT_ROW)%
    ;押したボタン列にあわせてキャラ指定
    SELECTCASE SELECT_COL
        CASE 0
            ;処理なし(条件的に来ない)
        CASE 1
            ; TARGET_CHARA_IDに最良キャラを入れる
            TARGET_CHARA_ID = BEST_ROLL_CHARA_CHOICE_PARTY(GETNUM(ABL, JUDGE_TYPE))
        CASE 2
            ; TARGET_CHARA_IDにあなたを入れる
            TARGET_CHARA_ID = MASTER
    ENDSELECT
    IF JUDGE_TYPE != "なし"
        ;キャラ指定あり、確認スキップONで関数を呼び出し
        CALL QST_PARTY_ROLL(LIST_GET(_LIST_JUDGE_VALUE, SELECT_ROW), TOINT(LIST_GET(_LIST_DIFFICULTY, SELECT_ROW)), 1, EXP_GAIN, , TARGET_CHARA_ID, 1)
        ROLL_RESULT = RESULT
        CHALLENGED_CHARA = RESULT:1
        IF RESULT != -1
            SETBIT EVENT_FLAG, SELECT_ROW + 1
            ;CALL QST_SET_EVENT_FLAG_BY_IDX(EVENT_FLAG)
            IF !ALLOW_RETRY
                CALL QST_SET_FLAGMAP(@"EVENT_{QST_NOWEV_LIST_IDX}_ROLL_RESULT", TOSTR(EVENT_FLAG))
            ENDIF
        ELSEIF RESULT == -1
            CLEARLINE LINECOUNT - FIRST_LINE
            ; キャンセルした場合には自動選出されたキャラのIDが入ったTARGET_CHARA_IDをリセットする(リセットしないと手動選択ができなくなる)
            TARGET_CHARA_ID = -1
            GOTO ASK_LOOP
        ENDIF
    ENDIF
    RESULT:1 = CHALLENGED_CHARA
    RESULT:2 = SELECT_ROW
    RESULTS = %LIST_GET(_LIST_JUDGE_VALUE, SELECT_ROW)%
    RETURN ROLL_RESULT

ELSE
    GOTO ASK_LOOP
ENDIF

;-------------------------------------------------
; パーティ内におけるロール最良キャラの自動選択
;-------------------------------------------------
@BEST_ROLL_CHARA_CHOICE_PARTY(判定パラメータ)
#FUNCTION
#DIM 判定パラメータ
#DIM CHECK_CHARA_ID
#DIM BEST_CHARA_ID

; 当該するパラメータが存在しない場合にはパーティの0番のキャラを最良と見なして処理する(全員が同じ値のパラメータを持つ場合と同じ結果)
IF 判定パラメータ == -1
    RETURNF TOINT(LIST_GET(_LIST_QST_PARTY, 0))
ENDIF

BEST_CHARA_ID = -1

FOR LOCAL, 0, QST_PARTYNUM
    CHECK_CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, LOCAL))
    ; 「-1番のキャラの能力」を確認させない様に
    IF BEST_CHARA_ID == -1
        BEST_CHARA_ID = CHECK_CHARA_ID
        CONTINUE
    ENDIF
    IF ABL:CHECK_CHARA_ID:判定パラメータ > ABL:BEST_CHARA_ID:判定パラメータ
        BEST_CHARA_ID = CHECK_CHARA_ID
    ENDIF
NEXT

RETURNF BEST_CHARA_ID


code:
;クエスト関連の広域変数
#DIM CONST QST_MAX_QUESTNUM = 100
#DIM CONST QST_MAX_EVENTNUM = 300
#DIM CONST QST_MAX_FLAGNUM = 10

#DIMS QST_QUEST_TYPE
#DIM QST_有効クエストID
#DIM QST_NOWEV
#DIM QST_NOWEV_LIST_IDX
#DIMS QST_MAPNAME
#DIMS _DIC_QST_EVENT_LIST, HO_MAX_MAPNUM, QST_MAX_EVENTNUM

;メニュー関連
#DIM  QST_GUILD_MENU_CATEGORY
#DIM  QST_SELECT_QUEST_ID
#DIM  QST_MENU_PAGE_LEFT
#DIMS QST_DIC_QUEST_FILTER

;クエスト参加メンバーのCHARA_IDを格納
#DIM  CONST QST_MAX_PARTY_PRESET = 6
#DIM  CONST QST_MAX_PARTYNUM = 6
#DIMS SAVEDATA _LIST_QST_PARTY_PRESET, QST_MAX_PARTY_PRESET
#DIM  SAVEDATA QST_SELECT_PARTY_PRESET
#DIMS SAVEDATA _LIST_QST_PARTY
#DIM QST_PARTYNUM

#DIM QST_TRAIN_EXIT_EVENT_ID
#DIMS _LIST_QST_TRAIN_EXIT_EVENT

#DIMS _LIST_INQUEST_MEMBER_EDIT_CANDIDATES
#DIMS _LIST_PARTY_PARTICIPANT_RECORD

;経路描画をコントロールするフラグ
#DIM QST_HIDE_PATH
;クエストイベントの調教ターン数
;TRAINでのターン数初期化時にこの変数から代入される
#DIM QST_調教ターン数
;この変数にイベントIDが格納されている場合(!=-1の場合)対象ID以外のイベントがスロットから実行不可になる
#DIM QST_イベント選択制限
;名誉点
#DIM SAVEDATA QST_PRESTIGE_POINT
;淫堕点
#DIM SAVEDATA QST_LEWD_POINT
;応急治療点
#DIM QST_応急治療点

;各クエストのフラグ管理用変数
;クエスト実行後もゲーム内でフラグを保持し続けたい場合は QST_SV_... を使用する
;繰り返し実行可能なクエストでの宝箱の取得状況管理などに
#DIM QST_FLAG, QST_MAX_QUESTNUM
#DIM SAVEDATA QST_SV_QUEST_FLAG, QST_MAX_QUESTNUM
#DIM SAVEDATA QST_SV_EVENT_FLAG, QST_MAX_QUESTNUM, QST_MAX_EVENTNUM
;クエストの攻略回数をカウント
#DIM SAVEDATA QST_SV_CLEAR_COUNT, QST_MAX_QUESTNUM

;定期性クエストのクールタイム管理
#DIM SAVEDATA QST_COOLTIME, QST_MAX_QUESTNUM

;ギルドメニューの得点引換在庫
#DIMS SAVEDATA QUEST_MENU_DIC_SHOP_STOCK_0, 20

;クエストの探索状態保持設定
#DIM  QST_SAVE_EXPLORED
;探索済ルームリスト
#DIMS SAVEDATA QST_LIST_EXPLORED_ROOM, QST_MAX_QUESTNUM

;グラフィカルマップ管理変数
#DIMS QST_GMAPDATA_PATH
#DIMS QST_GMAPDATA_FILENAME

;クエストで上昇する好感度関連
#DIM CONST QST_MAX_RELATION_UP = 100

;汎用イベント新増
#DIM CONST 汎用イベント_COUNT = 2
;CURRENTLY 1, CHANGE THIS CONST IF MORE IS WRITTEN
;#DIM 逆押し倒し_ID


code:
;-------------------------------------------------
;イベント関連の汎用関数
;各イベントから呼ばれる汎用可能な処理
;-------------------------------------------------
;-------------------------------------------------
;パーティ先頭のメンバーの名前を返す
;-------------------------------------------------
@QST_LEADER_NAME(複数形非表示 = 0)
#FUNCTIONS
#DIM 複数形非表示

IF !複数形非表示
    RETURNF ANAME(TOINT(LIST_GET(_LIST_QST_PARTY, 0)), QST_PARTYNUM)
ELSE
    RETURNF ANAME(TOINT(LIST_GET(_LIST_QST_PARTY, 0)))
ENDIF

@QST_LEADER_ID()
#FUNCTION
RETURNF TOINT(LIST_GET(_LIST_QST_PARTY, 0))

;-------------------------------------------------
;パーティメンバーから1名を無作為に選んでIDを返す式中関数
;-------------------------------------------------
@QST_RANDCHARA(リーダーを除く = 0)
#FUNCTION
#DIM リーダーを除く
#DIM CHARA_ID
IF LIST_COUNT(_LIST_QST_PARTY) < 2
    RETURNF TOINT(LIST_GET(_LIST_QST_PARTY, 0))
ENDIF
CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, RAND(リーダーを除く, QST_PARTYNUM)))
RETURNF CHARA_ID

;-------------------------------------------------
;指定キャラクターの体力を可変させる。
;0を下回った場合は行動不能フラグを立てる
;-------------------------------------------------
@QST_CHANGE_HP(CHARA_ID, VALUE, メッセージを出力する = 1)
#DIM CHARA_ID
#DIM VALUE
#DIM メッセージを出力する

IF VALUE >= 0
    BASE:CHARA_ID:体力 = MIN(MAXBASE:CHARA_ID:体力, BASE:CHARA_ID:体力 + VALUE)
    IF メッセージを出力する
        CALLF TAG_PRINT(@"%ANAME(CHARA_ID)%の体力が@C:{カラー_緑}@{VALUE}@/C@回復した", 1)
    ENDIF
    IF TCVAR:CHARA_ID:行動不能フラグ
        TCVAR:CHARA_ID:疲労深度 = 0
        TCVAR:CHARA_ID:行動不能フラグ = 0
        IF メッセージを出力する
            CALLF TAG_PRINT(@"@C:{カラー_注意}@%ANAME(CHARA_ID)%は意識を取り戻したようだ@/C@", 1)
        ENDIF
    ENDIF
ELSE
    BASE:CHARA_ID:体力 = MAX(0, BASE:CHARA_ID:体力 + VALUE)
    IF メッセージを出力する
        CALLF TAG_PRINT(@"%ANAME(CHARA_ID)%は@C:{カラー_オレンジ}@%REPLACE(TOSTR(VALUE), "-", "")%@/C@のダメージを受けた！", 1)
    ENDIF
    IF BASE:CHARA_ID:体力 == 0
        TCVAR:CHARA_ID:行動不能フラグ = 1
        IF メッセージを出力する
            CALLF TAG_PRINT(@"@C:{カラー_注意}@%ANAME(CHARA_ID)%は力尽きて倒れてしまった……@/C@", 1)
        ENDIF
    ENDIF
ENDIF

;-------------------------------------------------
; スキルクールタイムのリセット
;-------------------------------------------------
@QST_RESET_SKILL_COOLTIME(メッセージを出力する = 1)
#DIM メッセージを出力する
FOR LOCAL, 0, VARSIZE("ACTIVE_SKILL_COOLTIME")
    CVARSET ACTIVE_SKILL_COOLTIME, LOCAL, 0
NEXT
SIF メッセージを出力する == 1
    CALL PRINT_NOTICE("全員のスキルクールタイムがリセットされた！", カラー_緑)

;-------------------------------------------------
;;; 武器の入手イベント
;;;@arg WEAPON_ID   武器ID
;;;@args WEAPON_NAME 武器の表示名
;;;@arg 材質種類     武器の素材 (Ex. WPN_材質_鉄 詳細はVARIABLE_CLOTH.ERH参照)
;;;@arg WEAPON_RANK 強化値
;;;@args DIC_PASSIVE_WEAPON_SKILL 武器パッシブスキル、複数指定可 (EX. [WPN_UPWARD_ARMOR_DECAY:1][WPN_ADDITIONAL_ATTACK:1] のように[スキル定義名:スキルレベル]で指定)
;;;@args DIC_ACTIVE_WEAPON_SKILL 武器アクティブスキル 同上
;;; スキル定義名はWPN_SKILL_ACTIVE.xml,WPN_SKILL_PASSIVE.xml　参照
;;;@arg EQUIP_TYPE
;;;- 0 = 武器
;;;- 1 = レリック
;;;@arg 入手メッセージを表示
;;;- 0: 非表示
;;;- 1: 表示
;;;- 2: 入手/廃棄の選択肢を表示
;
;-------------------------------------------------
@QST_GET_WEAPON(WEAPON_ID, WEAPON_NAME, 材質種類, WEAPON_RANK = 0, DIC_PASSIVE_WEAPON_SKILL = "", DIC_ACTIVE_WEAPON_SKILL = "", EQUIP_TYPE = 0, 入手メッセージを表示 = 1)
#DIM  WEAPON_ID
#DIMS WEAPON_NAME
#DIM  材質種類
#DIM  WEAPON_RANK
#DIM  EQUIP_TYPE
#DIMS  DIC_PASSIVE_WEAPON_SKILL
#DIMS  DIC_ACTIVE_WEAPON_SKILL
#DIM  入手メッセージを表示
#DIM WEAPON_LIST_IDX
{
    CALL ADD_WEAPON_STOCK_LIST(WEAPON_ID
        , WEAPON_NAME
        , 材質種類
        , WEAPON_RANK
        , DIC_PASSIVE_WEAPON_SKILL
        , DIC_ACTIVE_WEAPON_SKILL
        , EQUIP_TYPE
        )
}
WEAPON_LIST_IDX = RESULT
CALL QST_GET_EQUIP_EVENT(WEAPON_LIST_IDX, 入手メッセージを表示)
RETURN RESULT

@QST_GET_EQUIP_EVENT(WEAPON_LIST_IDX, 入手メッセージを表示)
#DIM  WEAPON_ID
#DIMS WEAPON_NAME
#DIM  材質種類
#DIM  WEAPON_RANK
#DIM  EQUIP_TYPE
#DIMS  DIC_PASSIVE_WEAPON_SKILL
#DIMS  DIC_ACTIVE_WEAPON_SKILL
#DIM  入手メッセージを表示
#DIM WEAPON_LIST_IDX

EQUIP_TYPE = DT_CELL_GET("WEAPON_STOCK", WEAPON_LIST_IDX, "EQUIP_TYPE", 1)

SELECTCASE 入手メッセージを表示
    CASE 1
        CALL GET_WEAPON_PRINT_NAME(WEAPON_LIST_IDX)
        WEAPON_NAME = %RESULTS%
        LOCALS '= EQUIP_TYPE == 0 ? "武器" # "レリック"
        CALLF TAG_PRINT(@"@C:{カラー_注意}@Picked up %LOCALS%:%WEAPON_NAME%@/C@", 0)
    CASE 2
        CALL GET_WEAPON_PRINT_NAME(WEAPON_LIST_IDX)
        WEAPON_NAME = %RESULTS%
        LOCALS '= EQUIP_TYPE == 0 ? "武器" # "レリック"
        CALLF TAG_PRINT(@"@C:{カラー_注意}@Picked up %LOCALS%:%WEAPON_NAME%@/C@", 1)
        CALLF TAG_PRINT(@"@C:{カラー_注意}@(* When right clicked )@/C@", 1)
        ;品質 = LIMIT(品質, 0, VARSIZE("WPN_品質") - 1 )
        ;CALLF TAG_PRINT(@"%LOCALS%:@C:{カラー_注釈}@Picked up *%WPN_品質:品質%*@/C@@C:{WPN_品質_カラー:品質}@%WEAPON_NAME%@/C@", 1)

        CALL QST_GET_WEAPON_STR_DETAIL(WEAPON_LIST_IDX)
        CALLF TAG_PRINT(@"%RESULTS%", 1)
        CALL ASK_MULTI_WITH_RIGHT_CLICK(0, "Take", "Take and make favorite", "Get it and display it", "Discard")
        SELECTCASE RESULT
            CASE 0
            CASE 1
                CALL EQUIP_SWITCH_FAVORITE_FLAG(WEAPON_LIST_IDX)
            CASE 2
                DT_CELL_SET "WEAPON_STOCK", WEAPON_LIST_IDX, "ON_SALE_FLAG", 1, 1
                CALL GET_EQUIP_PRICE(WEAPON_LIST_IDX)
                DT_CELL_SET "WEAPON_STOCK", WEAPON_LIST_IDX, "PRICE", RESULT, 1
            CASE 3
                CALL DELETE_WEAPON(WEAPON_LIST_IDX)
                WEAPON_LIST_IDX = -1
            CASEELSE
        ENDSELECT
ENDSELECT
RETURN WEAPON_LIST_IDX

;QST_GET_WEAPONのラッパー関数
;必要なパラメータはすべて辞書形式で渡す
@QST_GET_EQUIP(DIC_EQUIP_DATA, 入手メッセージを表示 = 1)
#DIMS DIC_EQUIP_DATA
#DIM  入手メッセージを表示
#DIM  DYNAMIC WEAPON_DID
#DIMS DYNAMIC LIST_SKILL
#DIMS DYNAMIC DIC_ACTIVE_SKILL
#DIMS DYNAMIC DIC_PASSIVE_SKILL
#DIM  DYNAMIC PASSIVE_SKILL_SLOT
#DIM  DYNAMIC ACTIVE_SKILL_SLOT
#DIM  DYNAMIC PASSIVE_SKILL_SLOT_USED
#DIM  DYNAMIC ACTIVE_SKILL_SLOT_USED
#DIMS DYNAMIC DIC_ENCHANTED_PASSIVE_SKILL
#DIMS DYNAMIC DIC_ENCHANTED_ACTIVE_SKILL
#DIMS DYNAMIC SKILL_DEF_NAMES, 10

LIST_SKILL = %DIC_GET(DIC_EQUIP_DATA, "PASSIVE_WEAPON_SKILL")%
FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
    IF LOCAL == 0 || LOCAL % 2 == 0
        DIC_PASSIVE_SKILL += "[" + @"%LIST_GET(LIST_SKILL, LOCAL)%" + ":"
    ELSE
        DIC_PASSIVE_SKILL += @"%LIST_GET(LIST_SKILL, LOCAL)%]"
    ENDIF
NEXT

LIST_SKILL = %DIC_GET(DIC_EQUIP_DATA, "ENCHANTED_PASSIVE_WEAPON_SKILL")%
FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
    IF LOCAL == 0 || LOCAL % 2 == 0
        DIC_ENCHANTED_PASSIVE_SKILL += "[" + @"%LIST_GET(LIST_SKILL, LOCAL)%" + ":"
    ELSE
        DIC_ENCHANTED_PASSIVE_SKILL += @"%LIST_GET(LIST_SKILL, LOCAL)%]"
    ENDIF
NEXT

LIST_SKILL = %DIC_GET(DIC_EQUIP_DATA, "ACTIVE_WEAPON_SKILL")%
FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
    IF LOCAL == 0 || LOCAL % 2 == 0
        DIC_ACTIVE_SKILL += "[" + @"%LIST_GET(LIST_SKILL, LOCAL)%" + ":"
    ELSE
        DIC_ACTIVE_SKILL += @"%LIST_GET(LIST_SKILL, LOCAL)%]"
    ENDIF
NEXT

LIST_SKILL = %DIC_GET(DIC_EQUIP_DATA, "ENCHANTED_ACTIVE_WEAPON_SKILL")%
FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
    IF LOCAL == 0 || LOCAL % 2 == 0
        DIC_ENCHANTED_ACTIVE_SKILL += "[" + @"%LIST_GET(LIST_SKILL, LOCAL)%" + ":"
    ELSE
        DIC_ENCHANTED_ACTIVE_SKILL += @"%LIST_GET(LIST_SKILL, LOCAL)%]"
    ENDIF
NEXT

;パッシブスキル、アクティブスキルの連想配列は固定装備スキル、付呪装備スキルどちらも保持しているため
;連想配列を結合する。ただし同じ定義名のスキルは重複しないようにする
CALL DIC_KEYS(DIC_ENCHANTED_PASSIVE_SKILL)
ARRAYCOPY "RESULTS", "SKILL_DEF_NAMES"
FOR LOCAL, 0, RESULT
    IF DIC_CONTAINSKEY(DIC_PASSIVE_SKILL, SKILL_DEF_NAMES:LOCAL)
        CALLF TAG_PRINT(@"@C:{カラー_注意}@QST_GET_EQUIP:エラー#「%DIC_GET(DIC_EQUIP_DATA, "WEAPON_NAME")%」付呪スキルに固定スキルと同じスキルが含まれているため、%SKILL_DEF_NAMES:LOCAL%は付呪スキルとして追加されません@/C@", 1)
        DIC_ENCHANTED_PASSIVE_SKILL = %DIC_REMOVE(DIC_ENCHANTED_PASSIVE_SKILL, SKILL_DEF_NAMES:LOCAL)%
        CONTINUE
    ENDIF
    DIC_PASSIVE_SKILL = %DIC_SET(DIC_PASSIVE_SKILL, SKILL_DEF_NAMES:LOCAL, DIC_GET(DIC_ENCHANTED_PASSIVE_SKILL, SKILL_DEF_NAMES:LOCAL))%
NEXT
CALL DIC_KEYS(DIC_ENCHANTED_ACTIVE_SKILL)
ARRAYCOPY "RESULTS", "SKILL_DEF_NAMES"
FOR LOCAL, 0, RESULT
    IF DIC_CONTAINSKEY(DIC_ACTIVE_SKILL, SKILL_DEF_NAMES:LOCAL)
        CALLF TAG_PRINT(@"@C:{カラー_注意}@QST_GET_EQUIP:エラー#「%DIC_GET(DIC_EQUIP_DATA, "WEAPON_NAME")%」付呪スキルに固定スキルと同じスキルが含まれているため、%SKILL_DEF_NAMES:LOCAL%は付呪スキルとして追加されません@/C@", 1)
        DIC_ENCHANTED_ACTIVE_SKILL = %DIC_REMOVE(DIC_ENCHANTED_ACTIVE_SKILL, SKILL_DEF_NAMES:LOCAL)%
        CONTINUE
    ENDIF
    DIC_ACTIVE_SKILL = %DIC_SET(DIC_ACTIVE_SKILL, SKILL_DEF_NAMES:LOCAL, DIC_GET(DIC_ENCHANTED_ACTIVE_SKILL, SKILL_DEF_NAMES:LOCAL))%
NEXT

;スキルスロットの使用状況確認
PASSIVE_SKILL_SLOT = DIC_GETINT(DIC_EQUIP_DATA, "PASSIVE_SKILL_SLOT")
CALL DIC_KEYS(DIC_ENCHANTED_PASSIVE_SKILL)
PASSIVE_SKILL_SLOT_USED = RESULT
IF PASSIVE_SKILL_SLOT_USED > PASSIVE_SKILL_SLOT
    CALLF TAG_PRINT(@"@C:{カラー_注意}@QST_GET_EQUIP:エラー#「%DIC_GET(DIC_EQUIP_DATA, "WEAPON_NAME")%」指定されたスキルスロットより付呪パッシブスキルの数が多いため、装備追加処理を中止します@/C@", 1)
    RETURN -1
ENDIF

ACTIVE_SKILL_SLOT = DIC_GETINT(DIC_EQUIP_DATA, "ACTIVE_SKILL_SLOT")
CALL DIC_KEYS(DIC_ENCHANTED_ACTIVE_SKILL)
ACTIVE_SKILL_SLOT_USED = RESULT
IF ACTIVE_SKILL_SLOT_USED > ACTIVE_SKILL_SLOT
    CALLF TAG_PRINT(@"@C:{カラー_注意}@QST_GET_EQUIP:エラー#「%DIC_GET(DIC_EQUIP_DATA, "WEAPON_NAME")%」指定されたスキルスロットより付呪アクティブスキルの数が多いため、装備追加処理を中止します@/C@", 1)
    RETURN -1
ENDIF

;保有装備数が上限に到達している場合は廃棄処理を行う
CALL EQUIP_OWN_LIMIT_CHECK(EQUIP_TYPE)

VARI EQUIP_TYPE
VARI WEAPON_RANK
EQUIP_TYPE = DIC_GETINT(DIC_EQUIP_DATA, "EQUIP_TYPE")
WEAPON_RANK = DIC_GETINT(DIC_EQUIP_DATA, "WEAPON_RANK")
{
    DT_ROW_ADD "WEAPON_STOCK"
        ,"EQUIP_TYPE", EQUIP_TYPE
        ,"WEAPON_ID", DIC_GETINT(DIC_EQUIP_DATA, "WEAPON_ID")
        ,"WEAPON_NAME", DIC_GET(DIC_EQUIP_DATA, "WEAPON_NAME")
        ,"MATERIAL", DIC_GETINT(DIC_EQUIP_DATA, "MATERIAL")
        ,"WEAPON_RANK", WEAPON_RANK
        ,"PASSIVE_WEAPON_SKILL", DIC_PASSIVE_SKILL
        ,"ACTIVE_WEAPON_SKILL", DIC_ACTIVE_SKILL
        ,"PASSIVE_SKILL_SLOT", DIC_GETINT(DIC_EQUIP_DATA, "PASSIVE_SKILL_SLOT")
        ,"ACTIVE_SKILL_SLOT", DIC_GETINT(DIC_EQUIP_DATA, "ACTIVE_SKILL_SLOT")
        ,"ACTIVE_SKILL_SLOT_USED_SKILL_NAME", DIC_ENCHANTED_ACTIVE_SKILL
        ,"ACTIVE_SKILL_SLOT_USED", ACTIVE_SKILL_SLOT_USED
        ,"PASSIVE_SKILL_SLOT_USED_SKILL_NAME", DIC_ENCHANTED_PASSIVE_SKILL
        ,"PASSIVE_SKILL_SLOT_USED", PASSIVE_SKILL_SLOT_USED
        ,"EQUIP_CHARA_ID", -2
}
IF RESULT
    WEAPON_DID = RESULT
    CALL LOAD_WEAPON_DATA_TO_TABLE(WEAPON_DID, WEAPON_RANK, EQUIP_TYPE)
    ;装備入手時共通イベント
    CALL QST_GET_EQUIP_EVENT(WEAPON_DID, 入手メッセージを表示)
    RETURN RESULT
ELSE
    RETURN 0
ENDIF

;-------------------------------------------------
;;; 装備情報の明細行文字列を作成
;-------------------------------------------------
@QST_GET_WEAPON_STR_DETAIL(EQUIP_DID)
#DIM EQUIP_DID
#DIMS CALL_FROM
;印字カラム
#DIM  CONST COLUMN_LENGTH = 10, 10, 10, 10, 10, 10, 16,
#DIM  CONST COLUMN_PADDING = 0, 0, 0, 0, 0, 0, 0
;ステータスの表示順序
{
    #DIMS CONST   COLUMN_ORDER =
        "ATTACK"
        , "DEFENCE"
        , "ARMOR"
        , "MAG"
        , "AGILITY"
        , "HATE_RATE"
        , "TARGETING"
}
{
    #DIMS CONST   STATUS_NAME =
        "攻撃"
        , "防御"
        , "軽減"
        , "魔力"
        , "行動"
        , "敵視"
        , "選定"
}

VARS STRS
VARS COLUMN, 10
VARI COLUMN_IDX
VARI WEAPON_ID
VARI EQUIP_TYPE
VARI MATERIAL
VARS TOOLTIP
VARI F_COL

CALL GET_WEAPON_STOCK_TABLE(EQUIP_DID, "WEAPON_ID")
WEAPON_ID = RESULT
CALL GET_WEAPON_STOCK_TABLE(EQUIP_DID, "EQUIP_TYPE")
EQUIP_TYPE = RESULT

F_COL = カラー_白
STRS '= ""
;各パラメータ
VARI STATUS_IDX
FOR STATUS_IDX, 0, WPN_MAX_STATUSNUM
    IF COLUMN_ORDER:STATUS_IDX != "TARGETING"
        STRS += TAG_PRINT_SHAPE(@"@C:{カラー_注釈}@%STATUS_NAME:STATUS_IDX%: {DT_CELL_GET("WEAPON_STOCK", EQUIP_DID, COLUMN_ORDER:STATUS_IDX, 1)}@/C@", COLUMN_LENGTH:(STATUS_IDX + COLUMN_IDX), 1, 1)
    ELSEIF EQUIP_TYPE == 0
        STRS += TAG_PRINT_SHAPE(@"@C:{カラー_注釈}@%STATUS_NAME:STATUS_IDX%: %WPN_脅威選定文字列:DT_CELL_GET("WEAPON_STOCK", EQUIP_DID, COLUMN_ORDER:STATUS_IDX, 1)%@/C@", COLUMN_LENGTH:(STATUS_IDX + COLUMN_IDX), 1, 1)
    ENDIF
NEXT

STRS += "    "
;武器スキル_アクティブ
CALL GET_EQUIP_SKILL_LIST_STR(EQUIP_DID, 武器スキル_アクティブ)
STRS += RESULTS
;武器スキル_パッシブ
CALL GET_EQUIP_SKILL_LIST_STR(EQUIP_DID, 武器スキル_パッシブ)
STRS += RESULTS

RESULTS '= @"%STRS%"
RETURN

;-------------------------------------------------
;戦利品入手イベント
;-------------------------------------------------
@QST_GET_COMBAT_REWARD(_LIST_REWARD)
#DIMS _LIST_REWARD
#DIM  DYNAMIC IDX
#DIM  DYNAMIC ITEM_ID
#DIM  DYNAMIC ITEM_NUM

FOR LOCAL, 0, LIST_COUNT(_LIST_REWARD) / 2
    IDX = LOCAL * 2
    LOCALS = %LIST_GET(_LIST_REWARD, IDX)%
    ITEM_NUM = TOINT(LIST_GET(_LIST_REWARD, IDX + 1))
    IF LOCALS == "戦闘経験値"
        PRINTL
        CALL CC_ADD_COMBAT_EXP(ITEM_NUM)
    ELSEIF LOCALS == "MONEY"
        PRINTL
        LOCALS '= @"%TOSTR(ITEM_NUM, "###,###")%ディナリ相当の戦利品を\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
        CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
        MONEY += ITEM_NUM
    ELSEIF LOCALS == "PRESTIGE"
        PRINTL
        LOCALS '= @"名誉点を%TOSTR(ITEM_NUM, "###,###")%\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
        CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
        QST_PRESTIGE_POINT += ITEM_NUM
    ELSE
        PRINTL
        ITEM_ID = TOINT(LIST_GET(_LIST_REWARD, IDX))
        CALL GET_ITEM_NAME(ITEM_ID)
        LOCALS '= @"%RESULTS%を{ITEM_NUM}個\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
        CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
        CALL CHANGE_ITEM_STOCK(ITEM_ID, ITEM_NUM)
    ENDIF
NEXT

;-------------------------------------------------
; アイテム入手/喪失イベント
; QST_CHANGE_ITEM(@"{ITEM_銀インゴット},2,") のように指定する
; ※_LIST.ERBのリスト準拠なので末尾の','を忘れないように注意
;-------------------------------------------------
@QST_CHANGE_ITEM(_LIST_ITEM, DO_WAIT = 1, SHOW_MESSAGE = 1)
#DIMS _LIST_ITEM
#DIM  DO_WAIT
#DIM  SHOW_MESSAGE
#DIM  DYNAMIC IDX
#DIM  DYNAMIC ITEM_ID
#DIMS DYNAMIC SKILL_DEF_NAME
#DIM  DYNAMIC SKILL_GENRE
#DIM  DYNAMIC SKILL_LV
#DIMS DYNAMIC SKILL_NAME
#DIMS DYNAMIC WEAPON_DEF_NAME
#DIMS DYNAMIC WEAPON_NAME
#DIM  DYNAMIC DATA_IDX
#DIM  DYNAMIC ITEM_NUM
#DIMS DYNAMIC TOOLTIP
#DIM  ITER_I
#DIM  ITER_J

FOR LOCAL, 0, LIST_COUNT(_LIST_ITEM) / 2
    IDX = LOCAL * 2
    SELECTCASE LIST_GET(_LIST_ITEM, IDX)
        CASE "PRESTIGE_POINT", "名誉点"
            ITEM_NUM = TOINT(LIST_GET(_LIST_ITEM, IDX + 1))
            IF ITEM_NUM != 0
                LOCALS '= @"名誉点を%TOSTR(ABS(ITEM_NUM),"###,###,###")%点\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
                SIF SHOW_MESSAGE
                    CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
                QST_PRESTIGE_POINT += ITEM_NUM
            ENDIF
        CASE "LEWD_POINT", "淫堕点"
            ITEM_NUM = TOINT(LIST_GET(_LIST_ITEM, IDX + 1))
            IF ITEM_NUM != 0
                LOCALS '= @"淫堕点を%TOSTR(ABS(ITEM_NUM),"###,###,###")%点\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
                SIF SHOW_MESSAGE
                    CALLF TAG_PRINT(@"@C:{カラー_ピンク}@%LOCALS%@/C@", 1)
                QST_LEWD_POINT += ITEM_NUM
            ENDIF
        CASE "MONEY", "ディナリ"
            ITEM_NUM = TOINT(LIST_GET(_LIST_ITEM, IDX + 1))
            IF ITEM_NUM != 0
                LOCALS '= @"%TOSTR(ABS(ITEM_NUM),"###,###,##0")%ディナリを\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
                SIF SHOW_MESSAGE
                    CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
                MONEY += ITEM_NUM
            ENDIF
        CASEELSE
            ;数値情報はアイテムIDとみなす
            IF ISNUMERIC(LIST_GET(_LIST_ITEM, IDX))
                ITEM_ID = TOINT(LIST_GET(_LIST_ITEM, IDX))
                ITEM_NUM = TOINT(LIST_GET(_LIST_ITEM, IDX + 1))
                IF ITEM_NUM != 0
                    CALL GET_ITEM_NAME(ITEM_ID)
                    LOCALS '= @"%RESULTS%を{ABS(ITEM_NUM)}個\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
                    SIF SHOW_MESSAGE
                        CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
                    CALL CHANGE_ITEM_STOCK(ITEM_ID, ITEM_NUM)
                ENDIF
                ;ルーンが指定されているならルーンの在庫を更新する
            ELSEIF DIC_CONTAINSKEY(LIST_GET(_LIST_ITEM, IDX), "RUNE")
                SKILL_DEF_NAME = %DIC_GET(LIST_GET(_LIST_ITEM, IDX), "RUNE")%
                SKILL_GENRE = WPN_SKILL_GET_GENRE(SKILL_DEF_NAME)
                CALL SKILL_GET_NAME(SKILL_GENRE, SKILL_DEF_NAME, 1)
                SKILL_NAME = %RESULTS%
                ITEM_NUM  = LIST_GETINT(LIST_GET(_LIST_ITEM, IDX + 1))
                SKILL_LV = DIC_GETINT(LIST_GET(_LIST_ITEM, IDX), "SKILL_LV")
                CALL GET_SKILL_DESC(SKILL_DEF_NAME, SKILL_GENRE, SKILL_LV, 1)
                TOOLTIP = %RESULTS%
                SKILL_NAME '= @"@C:{SKILL_GENRE == 武器スキル_アクティブ ? カラー_オレンジ # カラー_黄緑}@<%SKILL_NAME%Lv{SKILL_LV}>@/C@"
                LOCALS '= @"@C:{カラー_注意}@ルーン@/C@:@B:DUMMY$%TOOLTIP%@%SKILL_NAME%@/B@を{ABS(ITEM_NUM)}個\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
                SIF SHOW_MESSAGE
                    CALLF TAG_PRINTH(@"%LOCALS%", 1)
                CALL RUNE_STOCK_CHANGE(SKILL_DEF_NAME, SKILL_LV, ITEM_NUM)
            ELSE
                ;その他文字列情報は装備情報とみなす(一旦入手イベントのみ)
                WEAPON_DEF_NAME = %LIST_GET(_LIST_ITEM, IDX)%
                ITEM_NUM = TOINT(LIST_GET(_LIST_ITEM, IDX + 1))
                IF ITEM_NUM > 0
                    DT_SELECT "EQUIP_DATA",@"WEAPON_DEF_NAME = '%WEAPON_DEF_NAME%'"
                    IF RESULT
                        DATA_IDX = RESULT:1
                        WEAPON_NAME = %DT_CELL_GETS("EQUIP_DATA", DATA_IDX, "WEAPON_NAME", 1)%
                        LOCALS '= @"【装備】%WEAPON_NAME%を{ABS(ITEM_NUM)}個\@ ITEM_NUM > 0 ? 手に入れた # 失った \@"
                        SIF SHOW_MESSAGE
                            CALLF TAG_PRINT(@"@C:{カラー_注意}@%LOCALS%@/C@", 1)
                        FOR ITER_J, 0, ITEM_NUM
                            {
                                CALL QST_GET_WEAPON(
                                    DT_CELL_GET("EQUIP_DATA", DATA_IDX, "WEAPON_ID", 1)
                                    ,WEAPON_NAME
                                    ,DT_CELL_GET("EQUIP_DATA", DATA_IDX, "MATERIAL", 1)
                                    ,DT_CELL_GET("EQUIP_DATA", DATA_IDX, "WEAPON_RANK", 1)
                                    ,DT_CELL_GETS("EQUIP_DATA", DATA_IDX, "PASSIVE_WEAPON_SKILL", 1)
                                    ,DT_CELL_GETS("EQUIP_DATA", DATA_IDX, "ACTIVE_WEAPON_SKILL", 1)
                                    ,DT_CELL_GET("EQUIP_DATA", DATA_IDX, "EQUIP_TYPE", 1)
                                    ,0
                                    )
                            }
                        NEXT
                        ;DEBUGPRINTFORML TEST:%DT_CELL_GETS("EQUIP_DATA", DATA_IDX, "PASSIVE_WEAPON_SKILL", 1)%
                    ELSE
                        CONTINUE
                    ENDIF
                ENDIF
            ENDIF
    ENDSELECT
NEXT
SIF DO_WAIT
    WAIT
RESULTS = %LOCALS%

;-------------------------------------------------
;パーティメンバーから任意の1キャラクターを選択
;-------------------------------------------------
@QST_SELECT_CHARA(キャンセルを許可 = 1, MESSAGE = "キャラクターを選択してください", SELECT_FUNC = "")
#DIM キャンセルを許可
#DIMS MESSAGE
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC INPUT_VALUE
#DIMS DYNAMIC SELECT_FUNC

PRINTL
PRINTFORML %MESSAGE%
PRINTL
FOR LOCAL, 0, QST_PARTYNUM
    CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, LOCAL))
    IF SELECT_FUNC != ""
        TRYCCALLFORM %SELECT_FUNC%(CHARA_ID)
            SIF !RESULT
                CONTINUE
        CATCH
        ENDCATCH
    ENDIF
    CALLF TAG_PRINT(@"@B:{CHARA_ID}@[%ANAME(CHARA_ID), 15, LEFT%]", 5)
NEXT
PRINTL
IF キャンセルを許可
    CALLF TAG_PRINT(@"@B:9999@[キャンセル]@/B@", 5)
    PRINTL
ENDIF
WHILE 1
    ONEINPUT
    CLEARLINE 1
    INPUT_VALUE = RESULT
    IF LIST_INDEXOF(_LIST_QST_PARTY, TOSTR(INPUT_VALUE)) != -1
        CHARA_ID = INPUT_VALUE
        RETURN CHARA_ID
    ELSEIF INPUT_VALUE == 9999
        RETURN -1
    ENDIF
WEND

;-------------------------------------------------
;パーティメンバーから複数のキャラクターを選択
;@SELECT_CHARA_LIST_MULTIを流用
; オプションは辞書形式で指定 "[KEY1:VALUE][KEY2:VALUE]..."
; ARGS:1
; DIC_OPTION
;  "ALLOW_CANCEL" …  1 = キャンセルを許可
;  "MIN_MEMBERNUM" … 最低人数
;  "MAX_MEMBERNUM" … 最高人数
;  "SELECTOR" … 選択条件関数を指定
;  "MESSAGE" … 選択時のメッセージ
;  "CANCEL_MESSAGE" … キャンセル時のメッセージ
;   ⇒STRFORMで解釈されるので式中関数を直接入力する
;    判定対象のキャラ登録番号の変数は"CHARA_ID"を使用
;    以下のように書くとパーティのうちあなたのみ選択可能になる
;    ex.[SELECTOR:{CHARA_ID == MASTER}]
; ARGS:2
;選択結果は以下の変数で返却される
; SELECTED_CHARA_NUM … 選択されたキャラの人数
; SELECTED_CHARA … 配列、選択されたキャラのCHARA_ID
;-------------------------------------------------
@QST_SELECT_CHARA_MULTI(DIC_OPTION)
#DIMS DIC_OPTION
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC INPUT_VALUE
;オプションの初期値
#DIM  DYNAMIC ALLOW_CANCEL = 1
#DIM  DYNAMIC MIN_MEMBERNUM = 0
#DIM  DYNAMIC MAX_MEMBERNUM = 6
#DIMS DYNAMIC MESSAGE = "キャラクターを選択してください"
#DIMS DYNAMIC CANCEL_MESSAGE = "止めておこう……"

;選択用関数のオプションを初期化
SELECTOR_FUNC_OPTION '= ""

IF DIC_CONTAINSKEY(DIC_OPTION, "ALLOW_CANCEL")
    ALLOW_CANCEL = TOINT(DIC_GET(DIC_OPTION, "ALLOW_CANCEL"))
ENDIF
IF DIC_CONTAINSKEY(DIC_OPTION, "MIN_MEMBERNUM")
    MIN_MEMBERNUM = TOINT(DIC_GET(DIC_OPTION, "MIN_MEMBERNUM"))
ENDIF
IF DIC_CONTAINSKEY(DIC_OPTION, "MAX_MEMBERNUM")
    MAX_MEMBERNUM = TOINT(DIC_GET(DIC_OPTION, "MAX_MEMBERNUM"))
ENDIF
IF DIC_CONTAINSKEY(DIC_OPTION, "MESSAGE")
    MESSAGE = %DIC_GET(DIC_OPTION, "MESSAGE")%
ENDIF
IF DIC_CONTAINSKEY(DIC_OPTION, "CANCEL_MESSAGE")
    CANCEL_MESSAGE = %DIC_GET(DIC_OPTION, "CANCEL_MESSAGE")%
ENDIF
IF DIC_CONTAINSKEY(DIC_OPTION, "SELECTOR")
    SELECTOR_FUNC_OPTION = %DIC_GET(DIC_OPTION, "SELECTOR")%
ENDIF

$ASK_LOOP
WHILE 1
    PRINTFORML %MESSAGE%
    PRINTL
    CALL SELECT_CHARA_LIST_INIT
    CALL SELECT_CHARA_LIST_MULTI_ONLY_LOGIC_SLG(MAX_MEMBERNUM, "PARTY_MEMBER", "QST_SELECT_CHARA_MULTI")
    IF SELECTED_CHARA_NUM >= MIN_MEMBERNUM
        RETURN
    ELSEIF ALLOW_CANCEL
        PRINTL
        PRINTFORMW %CANCEL_MESSAGE%
        PRINTL
        RETURN
    ELSE
        PRINTL
        PRINTFORMW 最低{MIN_MEMBERNUM}名キャラクターを選択してください
        PRINTL
        GOTO ASK_LOOP
    ENDIF
WEND

;-------------------------------------------------
; SELECT_FUNCで指定するよく使いそうな条件
;-------------------------------------------------
;誘蛾の色香持ちキャラのみ対象
@QST_CHARA_IS_SEDUCTIVE_FEMALE(CHARA_ID)
#DIM CHARA_ID
RETURN HAS_SKILL(CHARA_ID, "SEDUCTION", スキル_大分類_性技) && IS_FEMALE(CHARA_ID)

@SELECT_CHARA_LIST_SELECT_LOGIC_QST_SELECT_CHARA_MULTI(CHARA_ID)
#DIM CHARA_ID
#DIMS SELECTOR
SELECTOR = %STRFORM(SELECTOR_FUNC_OPTION)%
IF SELECTOR_FUNC_OPTION != ""
    RETURN TOINT(SELECTOR)
ENDIF

;-------------------------------------------------
;パーティメンバーから1名を選択し、行為判定を行う
;難易度補正値は千分率で指定
; 行為判定対象が引数に指定されている場合、キャラ選択を省略する
; 戻り値
; RESULT:0 キャンセル=-1, 失敗=0, 成功=1
; RESULT:1 行為判定を行ったキャラのCHARA_ID
;-------------------------------------------------
@QST_PARTY_ROLL(判定パラメータ名, 難易度補正値, キャンセルを許可 = 1, 獲得経験値 = 0, 失敗時経験点付与 = 1, TARGET_CHARA_ID = -1, 確認スキップ = 0)
#DIMS 判定パラメータ名
#DIM 難易度補正値
#DIM キャンセルを許可
#DIM 獲得経験値
#DIM 失敗時経験点付与
#DIM TARGET_CHARA_ID
#DIM 確認スキップ
#DIM DYNAMIC CHARA_ID
#DIM DYNAMIC INPUT_VALUE
#DIM DYNAMIC 判定パラメータ
#DIM DYNAMIC 判定値

VARSET RESULT
判定パラメータ = GETNUM(ABL, 判定パラメータ名)
;実行対象キャラ指定なし
IF TARGET_CHARA_ID == -1
    ;実行対象キャラが指定されていない場合は確認を飛ばせないのでフラグを折る
    確認スキップ = 0
    PRINTL
    PRINTFORMW 行為判定を行うキャラクターを選択してください
    PRINTL
    FOR LOCAL, 0, QST_PARTYNUM
        CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, LOCAL))
        判定値 = QST_GET_ROLL_SUCCESS_RATE(ABL:CHARA_ID:判定パラメータ, 難易度補正値)
        CALLF TAG_PRINT(@"@B:{CHARA_ID}@[%ANAME(CHARA_ID), 15, LEFT%] (%判定パラメータ名%:%TOSTR(ABL:CHARA_ID:判定パラメータ), 3, RIGHT%) @C:{カラー_注釈}@[成功確率:{MIN(100, 判定値 / 10)}\%]@/C@@/B@", 5)
    NEXT
    ;実行対象キャラ指定あり＆確認スキップフラグOFFの場合は実行確認を表示
ELSEIF !確認スキップ
    判定値 = QST_GET_ROLL_SUCCESS_RATE(ABL:TARGET_CHARA_ID:判定パラメータ, 難易度補正値)
    PRINTL
    CALLF TAG_PRINT(@"@C:{カラー_注意}@%ANAME(TARGET_CHARA_ID)%@/C@に判定を実行させますか？((%判定パラメータ名%:%TOSTR(ABL:TARGET_CHARA_ID:判定パラメータ), 3, RIGHT%) @C:{カラー_注釈}@[成功確率:{MIN(100, 判定値 / 10)}\%]@/C@)", 1)
    PRINTL
    CALLF TAG_PRINT(@"@B:{TARGET_CHARA_ID}@[実行する]@/B@", 5)
ENDIF
PRINTL
SIF キャンセルを許可 && !確認スキップ
    CALLF TAG_PRINT(@"@B:9999@[キャンセル]@/B@", 5)
WHILE 1
    ;通常時(確認スキップなし時)は入力処理(キャラ選択兼実行確認)で対象キャラを決定
    IF !確認スキップ
        ONEINPUT
        CLEARLINE 1
        INPUT_VALUE = RESULT
        ;確認スキップ時は入力処理を飛ばして対象キャラを決定
    ELSE
        INPUT_VALUE = TARGET_CHARA_ID
    ENDIF
    IF (LIST_INDEXOF(_LIST_QST_PARTY, TOSTR(INPUT_VALUE)) != -1) || (!FLAG:クエストモード && TARGET_CHARA_ID != -1 && INPUT_VALUE != 9999)
        CHARA_ID = INPUT_VALUE
        判定値 = QST_GET_ROLL_SUCCESS_RATE(ABL:CHARA_ID:判定パラメータ, 難易度補正値)
        PRINTL
        CALL PRINT_TITLE("成功判定", "ROLL")
        PRINTFORML %ANAME(CHARA_ID)%の成功確率 {MIN(100, 判定値 / 10)}\%
        CALL FL_PLAYSE("Dice_0.mp3")
        WAIT
        IF RAND:1000 < 判定値
            CALLF TAG_PRINT(@"　⇒　@C:{カラー_緑}@成功！@/C@", 1)
            CALL DRAW_PORTRAIT(CHARA_ID, "[感情:幸][サイズ:180px][POS_X:0]",,1)
            CALL KJ_EVENT(CHARA_ID, "クエスト_行為判定成功")
            PRINTW
            IF 獲得経験値
                CALL PRINT_ADD_EXP(CHARA_ID, @"%判定パラメータ名%経験値", 獲得経験値, 1)
                CALL TRAIN_AUTO_ABLUP(CHARA_ID)
            ENDIF
            CALL COLOR_LINE
            PRINTL
            WAIT
            RESULT:1 = CHARA_ID
            RETURN 1
        ELSE
            CALLF TAG_PRINT(@"　⇒　@C:{カラー_オレンジ}@失敗！@/C@", 1)
            CALL DRAW_PORTRAIT(CHARA_ID, "[感情:悲][サイズ:180px][POS_X:0]",,1)
            CALL KJ_EVENT(CHARA_ID, "クエスト_行為判定失敗")
            PRINTW
            IF 獲得経験値 && 失敗時経験点付与
                ;失敗時は獲得経験値の50%を与える
                CALL PRINT_ADD_EXP(CHARA_ID, @"%判定パラメータ名%経験値", 獲得経験値 / 2, 1)
                CALL TRAIN_AUTO_ABLUP(CHARA_ID)
            ENDIF
            CALL COLOR_LINE
            PRINTL
            WAIT
            RESULT:1 = CHARA_ID
            RETURN 0
        ENDIF
    ELSEIF INPUT_VALUE == 9999
        RETURN -1
    ENDIF
WEND

;判定成功率の計算
;・ステータスに比例して成功確率を積み増すとあっさりインフレしてしまうので
;　平方根(SQRT)を求めて逓減的な値にしてみる
;・難易度補正値と判定成功率は千分率(1000で100%)
@QST_GET_ROLL_SUCCESS_RATE(判定パラメータ値, 難易度補正値)
#FUNCTION
#DIM 判定パラメータ値
#DIM 難易度補正値
RETURNF SQRT(判定パラメータ値 * 100) * 10 - 難易度補正値

;-------------------------------------------------
;指定部位の衣装を損傷させる
;衣装損壊度増減 = 100 で破壊
;-------------------------------------------------
@QST_ARMOR_BREAK(CHARA_ID, 被覆部位, 衣装損壊度増減)
#DIM CHARA_ID
#DIM 被覆部位
#DIM 衣装損壊度増減

CALL IS_COVERED(CHARA_ID, 被覆部位)
IF RESULT:1 != 0
    衣装損壊率:CHARA_ID:(RESULT:0) += 衣装損壊度増減
    CALL QST_CHECK_ARMOR_BREAK(CHARA_ID)
    RETURN 1
ELSE
    RETURN 0
ENDIF

;-------------------------------------------------
;衣装損壊率判定
;衣装損壊率 >= 100 で破壊
;コマンド実行後の QST_EVENTCOMEND からも呼ばれる
;-------------------------------------------------
@QST_CHECK_ARMOR_BREAK(CHARA_ID)
#DIM CHARA_ID
#DIM DYNAMIC 衣装部位
#DIMS DYNAMIC 衣装描写
;衣装損壊判定
FOR 衣装部位, 0 ,CLOTH_PART_NUM
    IF 衣装損壊率:CHARA_ID:衣装部位 >= 100 && 衣装状態:CHARA_ID:衣装部位 == 0
        衣装状態:CHARA_ID:衣装部位 = 衣装状態_破
        CALL GET_CLOTH_DESC(衣装部位, (調教用衣装:CHARA_ID:衣装部位))
        衣装描写 '= RESULTS
        CALL FL_PLAYSE("Tear_0.mp3")
        CALLF TAG_PRINT(@"@C:{カラー_注意}@%ANAME(CHARA_ID)%の%衣装描写%が破れてしまった……@/C@", 1)
        WAIT
    ENDIF
NEXT

;-------------------------------------------------
; ランダムイベントセット処理
; 予めMAPDATAに指定したイベント配置箇所に対して、
; 指定数以上のイベントを非アクティブにする
;-------------------------------------------------
@QST_SET_RANDOM_EVENT(EVENT_ID, EVENT_NUM)
#DIM EVENT_ID
#DIM EVENT_NUM
#DIMS MAP_NAME
#DIMS KEY_NAME
#DIMS _LIST_EVENT
#DIMS _LIST_TO

LIMIT EVENT_NUM, 0, QST_MAX_EVENTNUM

CALL QST_GET_LIST_EVENT_IDX("EVENT_ID", TOSTR(EVENT_ID))
_LIST_EVENT = %RESULTS%
CALL LIST_SHUFFLE(_LIST_EVENT)

FOR LOCAL, 0, LIST_COUNT(_LIST_EVENT) - EVENT_NUM
    CALL QST_SET_EVENT_LIST(TOINT(LIST_GET(_LIST_EVENT, LOCAL)), "EVENT_STATE", "DEACTIVE")
NEXT

;-------------------------------------------------
; 特定のキーと値に合致するイベントを登録リストからリスト化して返す
;-------------------------------------------------
@QST_GET_LIST_EVENT_IDX(KEYS, VALUES)
#DIMS KEYS
#DIMS VALUES
#DIMS DYNAMIC _LIST_EVENT
FOR LOCAL, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(LOCAL, KEYS)
    SIF RESULT > 0
        RESULTS = %TOSTR(RESULT)%
    IF RESULTS == VALUES
        _LIST_EVENT = %LIST_ADD(_LIST_EVENT, TOSTR(LOCAL))%
    ENDIF
NEXT
RESULTS = %_LIST_EVENT%
RETURN

;-------------------------------------------------
; 特定のイベントが配置されているエリアの場所を返す
;-------------------------------------------------
@QST_GET_LIST_EVENT_PLACED_ROOM(EVENT_ID)
#DIM EVENT_ID
#DIMS DYNAMIC _LIST_ROOM
FOR LOCAL, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(LOCAL, "EVENT_ID")
    IF RESULT == EVENT_ID
        CALL QST_GET_EVENT_LIST(LOCAL, "ROOM_IDX")
        _LIST_ROOM = %LIST_ADD(_LIST_ROOM, TOSTR(RESULT))%
    ENDIF
NEXT
RESULTS = %_LIST_ROOM%
RETURN

;-------------------------------------------------
;極めて倒錯的な人物にはレイプを許容させる
;該当する人物が存在するかどうか判定
;-------------------------------------------------
@QST_GET_CHARA_CAN_ACCEPT_RAPE
#DIM CHARA_ID
#DIMS DYNAMIC _LIST_CHARA

FOR LOCAL, 0, QST_PARTYNUM
    CHARA_ID = TOINT((LIST_GET(_LIST_QST_PARTY, LOCAL)))
    SIF !CAN_RAPE_ACCEPT(CHARA_ID)
        CONTINUE
    _LIST_CHARA = %LIST_ADD(_LIST_CHARA, TOSTR(CHARA_ID))%
NEXT
SIF !LIST_COUNT(_LIST_CHARA)
    RETURN 0
RESULTS = %_LIST_CHARA%
RETURN 1

;-------------------------------------------------
; SELECT_CHARA_LIST関数でのキャラ選択時にクエストのパーティメンバーのみを表示
;-------------------------------------------------
@SELECT_CHARA_LIST_SHOW_LOGIC_PARTY_MEMBER(CHARA_ID)
#DIM CHARA_ID
IF LIST_INDEXOF(_LIST_QST_PARTY, TOSTR(CHARA_ID)) >= 0
    RETURN 1
ELSE
    RETURN 0
ENDIF

;-------------------------------------------------
;キャラ選択関数 @SELECT_CHARA_LIST_MULTI_ONLY_LOGIC_SLGから呼ばれるフィルター用関数
;主人公の狼藉に同調させるキャラクターは倒錯的な素質を持っている必要がある
;-------------------------------------------------
@SELECT_CHARA_LIST_SELECT_LOGIC_IS_RAPE_ACCEPTABLE(CHARA_ID)
#DIM CHARA_ID
RETURN CAN_RAPE_ACCEPT(CHARA_ID)

@CAN_RAPE_ACCEPT(CHARA_ID)
#FUNCTION
#DIM CHARA_ID
;主人公は自由意志
SIF CHARA_ID == MASTER
    RETURNF 1
;スケベモブも可
SIF CFLAG:CHARA_ID:スケベモブ
    RETURNF 1
;奴隷は盲目的に従う
SIF IS_SLAVE()
    RETURNF 1
;極めて倒錯的なキャラも同調する
SIF ABL:CHARA_ID:倒錯度 >= 800
    RETURNF 1
;倒錯的で加虐的なキャラ、極端に加虐的なキャラも可
SIF (ABL:CHARA_ID:倒錯度 >= 500 && ABL:CHARA_ID:サド >= 3) || ABL:CHARA_ID:サド >= 5
    RETURNF 1
RETURNF 0

;-------------------------------------------------
;擬似的なコマンド実行を行う
;クエストイベント側でソース変更や絶頂判定を行いたい場合に使用
;-------------------------------------------------
@QST_EXEC_DUMMYCOM(COM = 999)
#DIM COM
FLAG:DO_DUMMYCOM = 1
;DOTRAIN COM
CALL FL_DOTRAIN(COM)

;-------------------------------------------------
;対象キャラの通常性別<->ふたなり相互変換
;-------------------------------------------------
;●ふたなり薬から抜粋
@TO_FUTANARI(ARG:0)

;ＴＳ経験がなかった場合の元性別保存処理を追加
SIF TALENT:(ARG:0):元性別 == 0
    TALENT:(ARG:0):元性別 = TALENT:(ARG:0):性別 + 10

SELECTCASE TALENT:(ARG:0):性別
    CASE 0
        TALENT:(ARG:0):性別 = 3
    CASE 1
        TALENT:(ARG:0):性別 = 2
    CASE 2
        TALENT:(ARG:0):性別 = 1
    CASE 3
        TALENT:(ARG:0):性別 = 0
    CASE 4
        TALENT:(ARG:0):性別 = 5
    CASE 5
        TALENT:(ARG:0):性別 = 4
ENDSELECT

;-------------------------------------------------
;パーティ全滅判定
;-------------------------------------------------
@QST_IS_PARTY_KNOCKED_OUT
#DIM CHARA_ID
;調教後全滅判定
FOR LOCAL, 0, LIST_COUNT(_LIST_QST_PARTY)
    CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, LOCAL))
    IF TCVAR:CHARA_ID:行動不能フラグ == 1 || TCVAR:CHARA_ID:失神フラグ == 1
        CONTINUE
    ELSE
        RETURN 0
    ENDIF
NEXT
RETURN 1

;-------------------------------------------------
; 調教イベント用に生成したモブにメンバーの誘蛾の色香のレベルに応じたステータス補正をかける
;-------------------------------------------------
@QST_SET_SEDUCTION_EFFECT_TO_MOB(パーティの男性を含む = 0)
#DIM パーティの男性を含む
#DIM DYNAMIC CHARA_ID
#DIM DYNAMIC HIGHEST_SEDUCTION_LV

;パーティの女性メンバーの誘蛾の色香LVの最高値を算出
FOR LOCAL, 0, QST_PARTYNUM
    CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, LOCAL))
    IF IS_FEMALE(CHARA_ID) || パーティの男性を含む
        CALL SKILL_GET_LEVEL(CHARA_ID, スキル_大分類_性技, "SEDUCTION")
        SIF RESULT > HIGHEST_SEDUCTION_LV
            HIGHEST_SEDUCTION_LV = RESULT
    ENDIF
NEXT

;竿役生成
FOR CHARA_ID, 0, CHARANUM
    SIF !CFLAG:CHARA_ID:慰安モブ
        CONTINUE
    SIF !CFLAG:CHARA_ID:調教参加フラグ
        CONTINUE
    IF HIGHEST_SEDUCTION_LV > 0
        ABL:CHARA_ID:倒錯度 =  MAX(ABL:CHARA_ID:倒錯度, ABL:CHARA_ID:倒錯度 * LIMIT(HIGHEST_SEDUCTION_LV, 1, 3))
        ABL:CHARA_ID:性技 = MAX(ABL:CHARA_ID:性技, ABL:CHARA_ID:性技 * LIMIT(HIGHEST_SEDUCTION_LV, 1, 3))
        ABL:CHARA_ID:欲望 = MAX(ABL:CHARA_ID:欲望, ABL:CHARA_ID:欲望 * LIMIT(HIGHEST_SEDUCTION_LV, 1, 3))
        ABL:CHARA_ID:性交 = MAX(ABL:CHARA_ID:性交, ABL:CHARA_ID:性交 * LIMIT(HIGHEST_SEDUCTION_LV, 1, 3))
        ABL:CHARA_ID:Ｃ感 = MAX(ABL:CHARA_ID:Ｃ感, ((ABL:CHARA_ID:射精 + ABL:CHARA_ID:欲望)))
        IF HAS_PENIS(CHARA_ID)
            ABL:CHARA_ID:射精 = MAX(ABL:CHARA_ID:射精, ABL:CHARA_ID:射精 * LIMIT(HIGHEST_SEDUCTION_LV, 1, 3))
        ENDIF
    ENDIF
NEXT

;-------------------------------------------------
; 指定したキャラがパーティーに含まれるか。引数にCSTR:99を指定
;-------------------------------------------------
@PARTY_CONTAINS(CHARA_NAME)
#FUNCTION
#DIMS CHARA_NAME
IF LIST_INDEXOF(_LIST_QST_PARTY, TOSTR(NAME_TO_CHARA(CHARA_NAME))) == -1
    RETURNF 0	;含まれない
ELSE
    RETURNF 1	;含まれる
ENDIF

;-------------------------------------------------
; クエスト中のパーティー編集
;-------------------------------------------------
; 初期化
;-------------------------------------------------
@QST_EDIT_PARTY_INIT
_LIST_INQUEST_MEMBER_EDIT_CANDIDATES '= ""
;-------------------------------------------------
; クエスト中パーティー編集の候補キャラを登録
;-------------------------------------------------
@QST_ADD_PARTY_CANDIDATE(CHARA_ID)
#DIM CHARA_ID

IF !IS_VALID_ID(CHARA_ID)
    ;DEBUGPRINTFORML 無効なCHARA_ID {CHARA_ID}
    RETURN -1
ELSEIF LIST_INDEXOF(_LIST_INQUEST_MEMBER_EDIT_CANDIDATES, TOSTR(CHARA_ID)) != -1
    ;DEBUGPRINTFORML 登録済みのCHARA_ID {CHARA_ID}
    RETURN -1
ELSE
    _LIST_INQUEST_MEMBER_EDIT_CANDIDATES = %LIST_ADD(_LIST_INQUEST_MEMBER_EDIT_CANDIDATES, TOSTR(CHARA_ID))%
ENDIF
;-------------------------------------------------
; クエスト中パーティー編集の候補キャラを抹消
;-------------------------------------------------
@QST_REMOVE_PARTY_CANDIDATE(CHARA_ID)
#DIM CHARA_ID
#DIM INDEX
INDEX = LIST_INDEXOF(_LIST_INQUEST_MEMBER_EDIT_CANDIDATES, TOSTR(CHARA_ID))
IF INDEX == -1
    ;DEBUGPRINTFORML 指定されたキャラが候補リストに存在しません
    RETURN -1
ENDIF

_LIST_INQUEST_MEMBER_EDIT_CANDIDATES = %LIST_REMOVEAT(_LIST_INQUEST_MEMBER_EDIT_CANDIDATES, INDEX)%

;-------------------------------------------------
; クエスト中パーティー編集の候補キャラをキャラIDリストから登録
;-------------------------------------------------
@QST_ADD_PARTY_CANDIDATE_FROM_LIST(_LIST_CHARA_ID)
#DIMS _LIST_CHARA_ID

FOR LOCAL, 0, LIST_COUNT(_LIST_CHARA_ID)
    CALL QST_ADD_PARTY_CANDIDATE(LIST_GETINT(_LIST_CHARA_ID, LOCAL))
NEXT

;-------------------------------------------------
; クエスト中パーティー編集の候補キャラを現PTから登録
;-------------------------------------------------
@QST_ADD_PARTY_CANDIDATE_FROM_CURRENT_PARTY
CALL QST_ADD_PARTY_CANDIDATE_FROM_LIST(_LIST_QST_PARTY)

;-------------------------------------------------
; クエスト中パーティー編集の候補キャラとして、プリセットパーティーメンバーを登録
; 引数省略時はクエスト開始時に選択したプリセット
;-------------------------------------------------
@QST_ADD_PARTY_CANDIDATE_FROM_PARTY_PRESET(PRESET_ID = -1)
#DIM PRESET_ID

SIF PRESET_ID < 0
    PRESET_ID = QST_SELECT_PARTY_PRESET

CALL QST_ADD_PARTY_CANDIDATE_FROM_LIST(_LIST_QST_PARTY_PRESET:PRESET_ID)

;-------------------------------------------------
; メイン処理
; 事前登録した候補キャラリストから指定人数のパーティーを編成
; 候補人数が最大人数以下なら、キャラ選択は行わずそのまま登録する
;
; SKIP_CHARA_SELECT_IF_POSSIBLE: 0を指定すると、事前登録した候補人数が最大人数以下の場合でもキャラ選択を実施。
; RESULTS:0: PT新規加入者のリスト
; RESULTS:1: PT離脱者のリスト
;-------------------------------------------------
@QST_EDIT_PARTY(SELECT_MIN = 1, SELECT_MAX = QST_MAX_PARTYNUM, SKIP_CHARA_SELECT_IF_POSSIBLE = 1)
#DIM SELECT_MIN
#DIM SELECT_MAX
#DIM SKIP_CHARA_SELECT_IF_POSSIBLE

#DIM CHARA_ID
#DIM ITER_I

#DIM CANDIDATE_NUM

#DIMS _LIST_QST_PARTY_BEFORE_EDIT
#DIMS DYNAMIC _LIST_JOINED_PARTY
#DIMS DYNAMIC _LIST_LEFT_PARTY

CANDIDATE_NUM = LIST_COUNT(_LIST_INQUEST_MEMBER_EDIT_CANDIDATES)
SIF CANDIDATE_NUM < 1
    THROW パーティ登録候補者が指定されていません

_LIST_QST_PARTY_BEFORE_EDIT '= _LIST_QST_PARTY

CALL QST_EDIT_PARTY__SELECT_CHARA(SELECT_MIN, SELECT_MAX, SKIP_CHARA_SELECT_IF_POSSIBLE, CANDIDATE_NUM)

QST_PARTYNUM = LIST_COUNT(_LIST_QST_PARTY)

FOR ITER_I, 0, QST_PARTYNUM
    CHARA_ID = LIST_GETINT(_LIST_QST_PARTY, ITER_I)
    IF LIST_INDEXOF(_LIST_QST_PARTY_BEFORE_EDIT, TOSTR(CHARA_ID)) == -1
        CALL QST_EDIT_PARTY__DATA_SETTING_FOR_JOINED(CHARA_ID)
        CALL PRINT_NOTICE(@"%ANAME(CHARA_ID)%がパーティに参加した")
        _LIST_JOINED_PARTY = %LIST_ADD(_LIST_JOINED_PARTY, TOSTR(CHARA_ID))%
    ENDIF
NEXT
FOR ITER_I, 0, LIST_COUNT(_LIST_QST_PARTY_BEFORE_EDIT)
    CHARA_ID = LIST_GETINT(_LIST_QST_PARTY_BEFORE_EDIT, ITER_I)
    IF LIST_INDEXOF(_LIST_QST_PARTY, TOSTR(CHARA_ID)) == -1
        CALL QST_EDIT_PARTY__DATA_SETTING_FOR_LEFT(CHARA_ID)
        CALL PRINT_NOTICE(@"%ANAME(CHARA_ID)%がパーティから離脱した")
        _LIST_LEFT_PARTY = %LIST_ADD(_LIST_LEFT_PARTY, TOSTR(CHARA_ID))%
    ENDIF
NEXT

RESULTS:0 '= _LIST_JOINED_PARTY
RESULTS:1 '= _LIST_LEFT_PARTY

@QST_EDIT_PARTY__SELECT_CHARA(SELECT_MIN, SELECT_MAX, SKIP_CHARA_SELECT_IF_POSSIBLE, CANDIDATE_NUM)
#DIM SELECT_MIN
#DIM SELECT_MAX
#DIM SKIP_CHARA_SELECT_IF_POSSIBLE
#DIM CANDIDATE_NUM

#DIM ITER_I
#DIMS EDIT_MESSAGE

SELECT_MAX = LIMIT(SELECT_MAX, 1, QST_MAX_PARTYNUM)
SELECT_MIN = LIMIT(SELECT_MIN, 1, MIN(SELECT_MAX, CANDIDATE_NUM))

IF SELECT_MIN == SELECT_MAX
    EDIT_MESSAGE '= @"パーティを編成してください({SELECT_MIN}名)"
ELSE
    EDIT_MESSAGE '= @"パーティを編成してください({SELECT_MIN}～{SELECT_MAX}名)"
ENDIF

IF CANDIDATE_NUM <= SELECT_MAX && SKIP_CHARA_SELECT_IF_POSSIBLE == 1
    ;候補人数が最大人数に収まる場合はキャラ選択なし
    _LIST_QST_PARTY '= _LIST_INQUEST_MEMBER_EDIT_CANDIDATES
ELSE
    ;キャラ選択
    $ CHARA_SELECT
    PRINTFORML %EDIT_MESSAGE%
    CALL SELECT_CHARA_LIST_INIT
    FOR ITER_I, 0, QST_PARTYNUM
        SELECTED_CHARA:LIST_GETINT(_LIST_QST_PARTY, ITER_I) = 1
    NEXT
    CALL SELECT_CHARA_LIST_MULTI_ONLY_LOGIC_SLG(SELECT_MAX, "INQUEST_MEMBER_EDIT", "NONE")
    IF SELECTED_CHARA_NUM < SELECT_MIN
        PRINTFORMW {SELECT_MIN}名以上選択してください
        GOTO CHARA_SELECT
    ENDIF
    _LIST_QST_PARTY '= ""
    FOR ITER_I, 0, SELECTED_CHARA_NUM
        _LIST_QST_PARTY = %LIST_ADD(_LIST_QST_PARTY, TOSTR(SELECTED_CHARA:ITER_I))%
    NEXT
ENDIF

;-------------------------------------------------
; クエスト中パーティー加入に伴うキャラデータ等の設定
;-------------------------------------------------
@QST_EDIT_PARTY__DATA_SETTING_FOR_JOINED(CHARA_ID)
#DIM CHARA_ID
#DIM DYNAMIC IDX

;パーティー参加履歴を更新
SIF LIST_INDEXOF(_LIST_PARTY_PARTICIPANT_RECORD, TOSTR(CHARA_ID)) == -1
    _LIST_PARTY_PARTICIPANT_RECORD = %LIST_ADD(_LIST_PARTY_PARTICIPANT_RECORD, TOSTR(CHARA_ID))%

;MASTERは対象外
IF CHARA_ID == MASTER
    FLAG:クエスト_あなた不参加 = 0
    RETURN
ENDIF
;キャラデータ登録済み
IF HO_GET_CHARAIDXF(CHARA_ID) != -1
    CALL HO_SET_CHARAPLACE(CHARA_ID, HO_MASTER現在地)
    ;キャラデータ未登録
ELSE
    FOR IDX, 0, VARSIZE("_DIC_HO_CHARALIST")
        IF _DIC_HO_CHARALIST:IDX == "DELETED"
            _DIC_HO_CHARALIST:IDX '= @"[CHARA_ID:{CHARA_ID}][ROOM_IDX:{HO_MASTER現在地}]"
            BREAK
        ELSEIF _DIC_HO_CHARALIST:IDX == "-1"
            SIF IDX == MAX_CHARANUM - 1
                THROW ERROR:キャラ上限を超えました
            _DIC_HO_CHARALIST:IDX '= @"[CHARA_ID:{CHARA_ID}][ROOM_IDX:{HO_MASTER現在地}]"
            _DIC_HO_CHARALIST:(IDX + 1) '= "-1"
            BREAK
        ENDIF
    NEXT
    CFLAG:CHARA_ID:交流参加 = 1
    CFLAG:CHARA_ID:調教中帰らない = 1
ENDIF

CALL QST_ADD_COMPANION(CHARA_ID)

;-------------------------------------------------
; クエスト中パーティー離脱に伴うキャラデータ等の設定
;-------------------------------------------------
@QST_EDIT_PARTY__DATA_SETTING_FOR_LEFT(CHARA_ID)
#DIM CHARA_ID

;MASTERは対象外
IF CHARA_ID == MASTER
    FLAG:クエスト_あなた不参加 = 1
    RETURN
ENDIF
CALL HO_REMOVE_COMPANION(CHARA_ID)

;-------------------------------------------------
; SELECT_CHARA_LIST関数でのキャラ選択時に、クエスト中パーティ編集の候補メンバーを表示
;-------------------------------------------------
@SELECT_CHARA_LIST_SHOW_LOGIC_INQUEST_MEMBER_EDIT(CHARA_ID)
#DIM CHARA_ID
IF  LIST_INDEXOF(_LIST_INQUEST_MEMBER_EDIT_CANDIDATES, TOSTR(CHARA_ID)) >= 0
    RETURN 1
ELSE
    RETURN 0
ENDIF

;-------------------------------------------------
; クエスト中に現パーティーからキャラを外す
;-------------------------------------------------
@QST_REMOVE_CHARA_FROM_PARTY(CHARA_ID)
#DIM CHARA_ID

SIF LIST_INDEXOF(_LIST_QST_PARTY, TOSTR(CHARA_ID)) == -1
    THROW 指定されたキャラID({CHARA_ID})がパーティーに含まれません

CALL QST_EDIT_PARTY_INIT
CALL QST_ADD_PARTY_CANDIDATE_FROM_CURRENT_PARTY
CALL QST_REMOVE_PARTY_CANDIDATE(CHARA_ID)
CALL QST_EDIT_PARTY

;-------------------------------------------------
; クエスト中に現パーティーからキャラを選んで外す
;-------------------------------------------------
@QST_SELECT_AND_REMOVE_CHARA_FROM_PARTY(SELECT_MIN, SELECT_MAX = -1)
#DIM SELECT_MIN
#DIM SELECT_MAX
#DIM ITER_I

SIF SELECT_MAX < 0
    SELECT_MAX = SELECT_MIN

SELECT_MAX = LIMIT(SELECT_MAX, 1, QST_PARTYNUM - 1)
SELECT_MIN = LIMIT(SELECT_MIN, 1, MIN(SELECT_MAX, QST_PARTYNUM - 1))

SIF QST_PARTYNUM - SELECT_MIN < 1
    THROW パーティーメンバーを1名以下にはできません

$ CHARA_SELECT
IF SELECT_MIN == SELECT_MAX
    PRINTFORML パーティーから外すキャラを{SELECT_MIN}名選択してください。
ELSE
    PRINTFORML パーティーから外すキャラを{SELECT_MIN}～{SELECT_MAX}名選択してください
ENDIF
CALL SELECT_CHARA_LIST_INIT
CALL SELECT_CHARA_LIST_MULTI_ONLY_LOGIC_SLG(SELECT_MAX, "PARTY_MEMBER", "NONE")
IF SELECTED_CHARA_NUM < SELECT_MIN
    PRINTFORMW {SELECT_MIN}名以上選択してください
    GOTO CHARA_SELECT
ENDIF

CALL QST_EDIT_PARTY_INIT
CALL QST_ADD_PARTY_CANDIDATE_FROM_CURRENT_PARTY
FOR ITER_I, 0, SELECTED_CHARA_NUM
    CALL QST_REMOVE_PARTY_CANDIDATE(SELECTED_CHARA:ITER_I)
NEXT
CALL QST_EDIT_PARTY


code:
;-------------------------------------------------
; 汎用レリックガチャ
;-------------------------------------------------
@QST_RANDOM_EQUIP_LOOT_RELIC(TABLE_RANK = 0)
; #region
#DIM TABLE_RANK
#DIMS DYNAMIC DIC_WPN_PASSIVE
#DIMS DYNAMIC DIC_WPN_ACTIVE
#DIM  DYNAMIC WEAPON_ID
#DIMS DYNAMIC WEAPON_NAME
#DIMS DYNAMIC CATEGORY
#DIM  DYNAMIC MATERIAL
#DIM  DYNAMIC RANK

CATEGORY = %S_R("BRACELET/AMULET/NECKLACE/BOOTS/SHIELD/RING")%
;武器種ID
SELECTCASE CATEGORY
    CASE "BRACELET"
        WEAPON_ID = 1
    CASE "AMULET"
        WEAPON_ID = 2
    CASE "NECKLACE"
        WEAPON_ID = 3
    CASE "BOOTS"
        WEAPON_ID = 4
    CASE "SHIELD"
        WEAPON_ID = 5
    CASE "RING"
        WEAPON_ID = 6
ENDSELECT

;武器の材質
CALL RAND_WT_INIT()
IF TABLE_RANK < 1
    CALL RAND_WT_SET(WPN_材質_銅, 60)
ENDIF
CALL RAND_WT_SET(WPN_材質_鉄, 40)
CALL RAND_WT_SET(WPN_材質_鋼, 20)
CALL RAND_WT_SET(WPN_材質_銀, 10)
CALL RAND_WT_SET(WPN_材質_金, 2)
MATERIAL = RAND_WT_RESULT()

;武器ランク
CALL RAND_WT_INIT()
IF TABLE_RANK < 1
    CALL RAND_WT_SET(0, 60)
ENDIF
CALL RAND_WT_SET(1, 20)
CALL RAND_WT_SET(2, 15)
CALL RAND_WT_SET(3, 10 + TABLE_RANK * 5)
CALL RAND_WT_SET(4, 5  + TABLE_RANK * 5)

SELECTCASE RAND_WT_RESULT()
    CASE 0
        RANK = RAND:2
    CASE 1
        RANK = RAND(2, 4)
    CASE 2
        RANK = RAND(3, 6)
    CASE 3
        RANK = RAND(4, 8)
    CASE 4
        RANK = RAND(9, 10)
ENDSELECT

;スキル抽選
CALL QST_RANDOM_LOOT_EQUIP_SKILL_ROLL_RELIC(WEAPON_ID, TABLE_RANK)
DIC_WPN_ACTIVE = %RESULTS:0%
DIC_WPN_PASSIVE = %RESULTS:1%

;武器名
CALL GET_WEAPON_NAME(WEAPON_ID, 1)
WEAPON_NAME '= @"%WPN_材質別接頭文字:MATERIAL%の%RESULTS%"

CALL QST_GET_WEAPON(WEAPON_ID, WEAPON_NAME, MATERIAL, RANK, DIC_WPN_PASSIVE, DIC_WPN_ACTIVE, 1, 2)
DEBUGPRINTFORML %WEAPON_NAME%

;-------------------------------------------------
;;; レリック用のスキル抽選結果を[スキル名:スキルレベル]の辞書で返す
;;; - RETURN
;;; RESULTS:0 アクティブスキルの抽選結果
;;; RESULTS:1 パッシブスキルの抽選結果
;-------------------------------------------------
@QST_RANDOM_LOOT_EQUIP_SKILL_ROLL_RELIC(WEAPON_ID, TABLE_RANK = 0)
#DIM WEAPON_ID
#DIM TABLE_RANK
VARI EQUIP_CATEGORY
;抽選候補
VARS LIST_CANDIDATE_ACTIVE
VARS LIST_CANDIDATE_PASSIVE1
VARS LIST_CANDIDATE_PASSIVE2
VARS LIST_CANDIDATE_PASSIVE3
;抽選結果
VARS DIC_WPN_ACTIVE
VARS DIC_WPN_PASSIVE

VARSET RESULTS
TRYCCALLFORM GET_RELIC_TYPE_{WEAPON_ID}
    EQUIP_CATEGORY = RESULT
CATCH
    RETURN 0
ENDCATCH

CALL QST_RANDOM_LOOT_EQUIP_SKILL_GET_ROLL_CANDIDATE_LIST_RELIC(EQUIP_CATEGORY, TABLE_RANK)
LIST_CANDIDATE_ACTIVE = %RESULTS:0%
LIST_CANDIDATE_PASSIVE1 = %RESULTS:1%
LIST_CANDIDATE_PASSIVE2 = %RESULTS:2%
LIST_CANDIDATE_PASSIVE3 = %RESULTS:3%
VARS LIST_RESULT_ACTIVE
VARS LIST_RESULT_PASSIVE
VARS LIST_RESULT_PASSIVE1
VARS LIST_RESULT_PASSIVE2
VARS LIST_RESULT_PASSIVE3

VARI SKILL_CNT
;アクティブスキルの抽選
;レリックのアクティブスキルは最大でも1つ
CALL LIST_SHUFFLE(LIST_CANDIDATE_ACTIVE)
IF RAND:100 < 70 + TABLE_RANK * 10
    LIST_RESULT_ACTIVE = %LIST_ADD(LIST_RESULT_ACTIVE, LIST_GET(LIST_CANDIDATE_ACTIVE, 0))%
    SKILL_CNT ++
ENDIF

;パッシブスキルの抽選1 通常パッシブ
VARI I
CALL LIST_SHUFFLE(LIST_CANDIDATE_PASSIVE1)
FOR I, 0, LIST_COUNT(LIST_CANDIDATE_PASSIVE1)
    IF I >= 2 || SKILL_CNT >= 4 || !(RAND:100 < 70 + (TABLE_RANK * 10) - (I * 45))
        BREAK
    ENDIF
    LIST_RESULT_PASSIVE1 = %LIST_ADD(LIST_RESULT_PASSIVE1, LIST_GET(LIST_CANDIDATE_PASSIVE1, I))%
    SKILL_CNT ++
NEXT

;パッシブスキルの抽選2 ステータスブースト
CALL LIST_SHUFFLE(LIST_CANDIDATE_PASSIVE2)
FOR I, 0, LIST_COUNT(LIST_CANDIDATE_PASSIVE2)
    IF I >= 2 || SKILL_CNT >= 4 || !(RAND:100 < 75 + (TABLE_RANK * 10) - (I * 40))
        BREAK
    ENDIF
    LIST_RESULT_PASSIVE2 = %LIST_ADD(LIST_RESULT_PASSIVE2, LIST_GET(LIST_CANDIDATE_PASSIVE2, I))%
    SKILL_CNT ++
NEXT

;パッシブスキルの抽選3 耐性ブースト
CALL LIST_SHUFFLE(LIST_CANDIDATE_PASSIVE3)
FOR I, 0, LIST_COUNT(LIST_CANDIDATE_PASSIVE3)
    IF I >= 2 || SKILL_CNT >= 4 || (RAND:100 < 70 + (TABLE_RANK * 10) - (I * 40))
        BREAK
    ENDIF
    LIST_RESULT_PASSIVE3 = %LIST_ADD(LIST_RESULT_PASSIVE3, LIST_GET(LIST_CANDIDATE_PASSIVE3, I))%
    SKILL_CNT ++
NEXT
LIST_RESULT_PASSIVE = %LIST_RESULT_PASSIVE1%%LIST_RESULT_PASSIVE2%%LIST_RESULT_PASSIVE3%

VARS SKILL_DEF_NAME
VARI MAX_SKILL_LV
VARI SKILL_LV
VARI SKILL_LV_RANGE
VARI LEVEL_TABLE
;抽選結果に基づくスキルの辞書を作成
;アクティブスキル
FOR I, 0, LIST_COUNT(LIST_RESULT_ACTIVE)
    SKILL_DEF_NAME = %LIST_GET(LIST_RESULT_ACTIVE, I)%
    CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_アクティブ)
    SIF RESULTS == ""
        CONTINUE
    MAX_SKILL_LV = TOINT(RESULTS)
    SKILL_LV_RANGE = MAX(MAX_SKILL_LV / 3, 1)
    CALL RAND_WT_INIT()
    CALL RAND_WT_SET(1, 95 - (TABLE_RANK * 25))
    CALL RAND_WT_SET(2, 5 + TABLE_RANK * 25)
    LEVEL_TABLE = RAND_WT_RESULT()
    SKILL_LV = LIMIT(RAND((LEVEL_TABLE - 1) * SKILL_LV_RANGE, LEVEL_TABLE * SKILL_LV_RANGE + 1), 1, MAX_SKILL_LV)
    DIC_WPN_ACTIVE = %DIC_SET(DIC_WPN_ACTIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
NEXT

;パッシブスキル
FOR I, 0, LIST_COUNT(LIST_RESULT_PASSIVE)
    SKILL_DEF_NAME = %LIST_GET(LIST_RESULT_PASSIVE, I)%
    CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_パッシブ)
    SIF RESULTS == ""
        CONTINUE
    MAX_SKILL_LV = TOINT(RESULTS)
    SKILL_LV_RANGE = MAX(MAX_SKILL_LV / 3, 1)
    CALL RAND_WT_INIT()
    CALL RAND_WT_SET(1, 95)
    CALL RAND_WT_SET(2, 5 + TABLE_RANK * 10)
    LEVEL_TABLE = RAND_WT_RESULT()
    SKILL_LV = LIMIT(RAND((LEVEL_TABLE - 1) * SKILL_LV_RANGE, LEVEL_TABLE * SKILL_LV_RANGE), 1, MAX_SKILL_LV)
    DIC_WPN_PASSIVE = %DIC_SET(DIC_WPN_PASSIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
NEXT

RESULTS:0 = %DIC_WPN_ACTIVE%
RESULTS:1 = %DIC_WPN_PASSIVE%

RETURN 1

;-------------------------------------------------
;;; レリック用のスキル抽選の候補リストを作成
;;; - RETURN
;;; RESULTS:0 アクティブスキル候補リスト
;;; RESULTS:1 パッシブスキル候補リスト
;;; RESULTS:2 パッシブスキル候補リスト(ステータスブースト)
;;; RESULTS:3 パッシブスキル候補リスト(耐性ブースト)
;-------------------------------------------------
@QST_RANDOM_LOOT_EQUIP_SKILL_GET_ROLL_CANDIDATE_LIST_RELIC(EQUIP_CATEGORY, TABLE_RANK = 0)
#DIM EQUIP_CATEGORY
#DIM TABLE_RANK
#DIM IS_ACTIVE_SKILL

VARS LIST_CANDIDATE_ACTIVE
VARS LIST_CANDIDATE_PASSIVE1
VARS LIST_CANDIDATE_PASSIVE2
VARS LIST_CANDIDATE_PASSIVE3
SELECTCASE EQUIP_CATEGORY
    CASE WPN_装備種類_腕輪
        LIST_CANDIDATE_ACTIVE  += "WPN_RECOVER_STUN_ALL," ;鼓舞
        LIST_CANDIDATE_ACTIVE  += "WPN_ADD_FRAGILE," ;穿孔
        LIST_CANDIDATE_PASSIVE1 += "WPN_UPWARD_ARMOR_DECAY," ;侵徹
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADDITIONAL_ATTACK," ;追撃
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_POISON," ;毒牙
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_MAG_BONUS," ;魔力＋
    CASE WPN_装備種類_護符
        LIST_CANDIDATE_ACTIVE += "WPN_ADD_CAST_SELF," ;スペルブースト
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_SONG_AT_START," ;残響
        LIST_CANDIDATE_PASSIVE1 += "WPN_DECOY_AMPLIFIER," ;幻影投影
        LIST_CANDIDATE_PASSIVE2 += "WPN_ARMOR_BONUS," ;軽減値＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_STUN," ;スタン耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_POISON," ;毒耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_BURN," ;燃焼耐性＋
    CASE WPN_装備種類_首飾
        LIST_CANDIDATE_ACTIVE += "WPN_RECOVER_STUN_ALL," ;鼓舞
        LIST_CANDIDATE_ACTIVE += "WPN_ADD_MAG_GUARD," ;ルーンシールド
        LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_PENETRATE," ;魔防貫通
        LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_DEFENCE_UP," ;ルーンコート
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_STUN," ;スタン耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_POISON," ;毒耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_BURN," ;燃焼耐性＋
    CASE WPN_装備種類_盾
        LIST_CANDIDATE_ACTIVE += "WPN_ADD_MAG_GUARD," ;ルーンシールド
        LIST_CANDIDATE_ACTIVE += "WPN_FRONT_DEFENCE," ;前衛防御
        LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_DEFENCE_UP," ;ルーンコート
        LIST_CANDIDATE_PASSIVE2 += "WPN_ARMOR_BONUS," ;軽減値＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_STUN," ;スタン耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_POISON," ;毒耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_BURN," ;燃焼耐性＋
    CASE WPN_装備種類_指輪
        LIST_CANDIDATE_ACTIVE += "WPN_ADD_CAST_SELF," ;スペルブースト
        LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_PENETRATE," ;魔防貫通
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_CAST_AT_START," ;ルーンプリローダ
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_MAG_BONUS," ;魔力＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
    CASE WPN_装備種類_靴
        LIST_CANDIDATE_PASSIVE1 += "WPN_TRAMPLE," ;蹂躙
        LIST_CANDIDATE_PASSIVE2 += "WPN_ARMOR_BONUS," ;軽減値＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_MAG_BONUS," ;魔力＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
    CASE WPN_装備種類_楽器
        LIST_CANDIDATE_ACTIVE  += "WPN_RECOVER_STUN_ALL," ;鼓舞
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_SONG_AT_START," ;残響
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
    CASE WPN_装備種類_兜, WPN_装備種類_鎧
        LIST_CANDIDATE_ACTIVE += "WPN_ADD_MAG_GUARD," ;ルーンシールド
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;軽減値＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_STUN," ;スタン耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_POISON," ;毒耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_BURN," ;燃焼耐性＋
    CASE WPN_装備種類_マント
        LIST_CANDIDATE_ACTIVE += "WPN_MAG_DEFENCE_UP," ;ルーンシールド
        LIST_CANDIDATE_PASSIVE1 += "WPN_DECOY_AMPLIFIER," ;幻影投影
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_STUN," ;スタン耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_POISON," ;毒耐性＋
        LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_BURN," ;燃焼耐性＋
ENDSELECT

RESULTS:0 = %LIST_CANDIDATE_ACTIVE%
RESULTS:1 = %LIST_CANDIDATE_PASSIVE1%
RESULTS:2 = %LIST_CANDIDATE_PASSIVE2%
RESULTS:3 = %LIST_CANDIDATE_PASSIVE3%
RETURN


code:
;-------------------------------------------------
; 汎用ルーンガチャ
;-------------------------------------------------
@QST_RANDOM_EQUIP_LOOT_RUNE(TABLE_RANK = 0)
; #region
#DIM TABLE_RANK

VARS SKILL_DEF_NAME
VARI SKILL_LV
;スキル抽選
CALL QST_RANDOM_LOOT_EQUIP_SKILL_ROLL_RUNE(TABLE_RANK)
SIF !RESULT
    RETURN
SKILL_LV = RESULT
SKILL_DEF_NAME = %RESULTS%

CALL QST_CHANGE_ITEM(@"[RUNE:%SKILL_DEF_NAME%][SKILL_LV:{SKILL_LV}],1,")

RETURN

;-------------------------------------------------
;;; ルーン用のスキル抽選結果を返す
;;; - RETURN
;;; RESULT:0 スキルレベル
;;; RESULTS:0 スキル名
;;;
;-------------------------------------------------
@QST_RANDOM_LOOT_EQUIP_SKILL_ROLL_RUNE(TABLE_RANK = 0)
#DIM TABLE_RANK

;抽選候補
VARS LIST_CANDIDATE_ACTIVE
VARS LIST_CANDIDATE_PASSIVE1
VARS LIST_CANDIDATE_PASSIVE2
VARS LIST_CANDIDATE_PASSIVE3

CALL QST_RANDOM_LOOT_EQUIP_SKILL_GET_ROLL_CANDIDATE_LIST_RUNE(TABLE_RANK)
LIST_CANDIDATE_ACTIVE = %RESULTS:0%
LIST_CANDIDATE_PASSIVE1 = %RESULTS:1%
LIST_CANDIDATE_PASSIVE2 = %RESULTS:2%
LIST_CANDIDATE_PASSIVE3 = %RESULTS:3%
VARS LIST_CANDIDATE
VARI IS_ACTIVE_SKILL
VARS SKILL_DEF_NAME

;スキルの抽選
CALL RAND_WT_INIT()
CALL RAND_WT_SET(0, 40)
CALL RAND_WT_SET(1, 25)
CALL RAND_WT_SET(2, 25)
CALL RAND_WT_SET(3, 25)

SELECTCASE RAND_WT_RESULT()
    CASE 0
        LIST_CANDIDATE = %LIST_CANDIDATE_ACTIVE%
        IS_ACTIVE_SKILL = 1
    CASE 1
        LIST_CANDIDATE = %LIST_CANDIDATE_PASSIVE1%
    CASE 2
        LIST_CANDIDATE = %LIST_CANDIDATE_PASSIVE2%
    CASE 3
        LIST_CANDIDATE = %LIST_CANDIDATE_PASSIVE3%
ENDSELECT
CALL LIST_SHUFFLE(LIST_CANDIDATE)
SKILL_DEF_NAME = %LIST_GET(LIST_CANDIDATE, 0)%

;抽選結果に基づくレベルの決定
VARI MAX_SKILL_LV
VARI SKILL_LV
VARI SKILL_LV_RANGE
VARI LEVEL_TABLE

IF IS_ACTIVE_SKILL == 1
    CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_アクティブ)
ELSE
    CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_パッシブ)
ENDIF
SIF RESULTS == ""
    RETURN 0
MAX_SKILL_LV = TOINT(RESULTS)
SKILL_LV_RANGE = MAX(MAX_SKILL_LV / 3, 1)
CALL RAND_WT_INIT()
CALL RAND_WT_SET(1, 95 - (TABLE_RANK * 25))
CALL RAND_WT_SET(2, 5 + TABLE_RANK * 25)
LEVEL_TABLE = RAND_WT_RESULT()
SKILL_LV = LIMIT(RAND((LEVEL_TABLE - 1) * SKILL_LV_RANGE, LEVEL_TABLE * SKILL_LV_RANGE + 1), 1, MAX_SKILL_LV)

RESULTS = %SKILL_DEF_NAME%
RETURN SKILL_LV

;-------------------------------------------------
;;; ルーン用のスキル抽選の候補リストを作成
;;; - RETURN
;;; RESULTS:0 アクティブスキル候補リスト
;;; RESULTS:1 パッシブスキル候補リスト
;;; RESULTS:2 パッシブスキル候補リスト(ステータスブースト)
;;; RESULTS:3 パッシブスキル候補リスト(耐性ブースト)
;-------------------------------------------------
@QST_RANDOM_LOOT_EQUIP_SKILL_GET_ROLL_CANDIDATE_LIST_RUNE(TABLE_RANK = 0)
#DIM TABLE_RANK
#DIM IS_ACTIVE_SKILL

VARS LIST_CANDIDATE_ACTIVE
VARS LIST_CANDIDATE_PASSIVE1
VARS LIST_CANDIDATE_PASSIVE2
VARS LIST_CANDIDATE_PASSIVE3

;アクテイブスキル
LIST_CANDIDATE_ACTIVE += "WPN_SMITE," ;重撃
LIST_CANDIDATE_ACTIVE  += "WPN_FATAL_ATTACK," ;致命打
LIST_CANDIDATE_ACTIVE  += "WPN_RECOVER_STUN_ALL," ;鼓舞
LIST_CANDIDATE_ACTIVE  += "WPN_ADD_FRAGILE," ;穿孔
LIST_CANDIDATE_ACTIVE  += "WPN_ADD_CAST_SELF," ;スペルブースト
LIST_CANDIDATE_ACTIVE  += "WPN_RECOVER_STUN_ALL," ;鼓舞
LIST_CANDIDATE_ACTIVE  += "WPN_ADD_MAG_GUARD," ;ルーンシールド

;パッシブスキル1
LIST_CANDIDATE_PASSIVE1 += "WPN_UPWARD_ARMOR_DECAY," ;侵徹
LIST_CANDIDATE_PASSIVE1 += "WPN_ADDITIONAL_ATTACK," ;追撃
LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_POISON," ;毒牙
LIST_CANDIDATE_PASSIVE1 += "WPN_DECOY_AMPLIFIER," ;幻影投影
LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_PENETRATE," ;魔防貫通
LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_DEFENCE_UP," ;ルーンコート

IF TABLE_RANK > 1
    LIST_CANDIDATE_PASSIVE1 += "WPN_ADDITIONAL_ATTACK," ;追撃
    LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_SONG_AT_START," ;残響
    LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_CAST_AT_START," ;ルーンプリローダ
ENDIF

;パッシブスキル2(ステータスブースト)
LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
LIST_CANDIDATE_PASSIVE2 += "WPN_MAG_BONUS," ;魔力＋
LIST_CANDIDATE_PASSIVE2 += "WPN_ARMOR_BONUS," ;軽減値＋
LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋

;パッシブスキル3(耐性ブースト)
LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_STUN," ;スタン耐性＋
LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_POISON," ;毒耐性＋
LIST_CANDIDATE_PASSIVE3 += "WPN_BOOST_REGIST_BURN," ;燃焼耐性＋

RESULTS:0 = %LIST_CANDIDATE_ACTIVE%
RESULTS:1 = %LIST_CANDIDATE_PASSIVE1%
RESULTS:2 = %LIST_CANDIDATE_PASSIVE2%
RESULTS:3 = %LIST_CANDIDATE_PASSIVE3%

RETURN


code:
;-------------------------------------------------
; 汎用レリックガチャ
;-------------------------------------------------
@QST_RANDOM_EQUIP_LOOT_WEAPON(TABLE_RANK = 0)
; #region
#DIM TABLE_RANK
#DIMS DYNAMIC DIC_WPN_PASSIVE
#DIMS DYNAMIC DIC_WPN_ACTIVE
#DIM  DYNAMIC WEAPON_ID
#DIMS DYNAMIC WEAPON_NAME
#DIMS DYNAMIC CATEGORY
#DIM  DYNAMIC MATERIAL
#DIM  DYNAMIC RANK

CATEGORY = %S_R("SHORT_SWORD/LONG_SWORD/AXE/GUN")%
;武器種ID
SELECTCASE CATEGORY
    CASE "SHORT_SWORD"
        WEAPON_ID = TOINT(S_R("1/5"))
    CASE "LONG_SWORD"
        WEAPON_ID = 2
    CASE "AXE"
        WEAPON_ID = 3
    CASE "GUN"
        WEAPON_ID = 6
ENDSELECT

;武器の材質
CALL RAND_WT_INIT()
IF TABLE_RANK < 1
    CALL RAND_WT_SET(WPN_材質_鉄, 50)
ENDIF
CALL RAND_WT_SET(WPN_材質_鋼, 30 + TABLE_RANK * 10)
CALL RAND_WT_SET(WPN_材質_銀, 20 + TABLE_RANK * 5)
MATERIAL = RAND_WT_RESULT()

;武器ランク
CALL RAND_WT_INIT()
CALL RAND_WT_SET(0, 70)
CALL RAND_WT_SET(1, 20 + TABLE_RANK * 10)
CALL RAND_WT_SET(2, 10 + TABLE_RANK * 5)
SELECTCASE RAND_WT_RESULT()
    CASE 0
        RANK = RAND:2
    CASE 1
        RANK = RAND(2, 4)
    CASE 2
        RANK = RAND(3, 6)
ENDSELECT

;スキル抽選
CALL QST_RANDOM_LOOT_EQUIP_SKILL_ROLL_WEAPON(WEAPON_ID, TABLE_RANK)
DIC_WPN_ACTIVE = %RESULTS:0%
DIC_WPN_PASSIVE = %RESULTS:1%

;武器名
CALL GET_WEAPON_NAME(WEAPON_ID, 0)
WEAPON_NAME '= @"%WPN_材質別接頭文字:MATERIAL%の%RESULTS%"

CALL QST_GET_WEAPON(WEAPON_ID, WEAPON_NAME, MATERIAL, RANK, DIC_WPN_PASSIVE, DIC_WPN_ACTIVE, 0, 2)

;-------------------------------------------------
;;; レリック用のスキル抽選結果を[スキル名:スキルレベル]の辞書で返す
;;; - RETURN
;;; RESULTS:0 アクティブスキルの抽選結果
;;; RESULTS:1 パッシブスキルの抽選結果
;-------------------------------------------------
@QST_RANDOM_LOOT_EQUIP_SKILL_ROLL_WEAPON(WEAPON_ID, TABLE_RANK = 0)
#DIM WEAPON_ID
#DIM TABLE_RANK
VARI EQUIP_CATEGORY
;抽選候補
VARS LIST_CANDIDATE_ACTIVE
VARS LIST_CANDIDATE_PASSIVE1
VARS LIST_CANDIDATE_PASSIVE2
VARS LIST_CANDIDATE_PASSIVE3
;抽選結果
VARS DIC_WPN_ACTIVE
VARS DIC_WPN_PASSIVE

VARSET RESULTS
TRYCCALLFORM GET_WEAPON_TYPE_{WEAPON_ID}
    EQUIP_CATEGORY = RESULT
CATCH
    RETURN 0
ENDCATCH

CALL QST_RANDOM_LOOT_EQUIP_SKILL_GET_ROLL_CANDIDATE_LIST_WEAPON(EQUIP_CATEGORY, TABLE_RANK)
LIST_CANDIDATE_ACTIVE = %RESULTS:0%
LIST_CANDIDATE_PASSIVE1 = %RESULTS:1%
LIST_CANDIDATE_PASSIVE2 = %RESULTS:2%
LIST_CANDIDATE_PASSIVE3 = %RESULTS:3%
VARS LIST_RESULT_ACTIVE
VARS LIST_RESULT_PASSIVE
VARS LIST_RESULT_PASSIVE1
VARS LIST_RESULT_PASSIVE2
VARS LIST_RESULT_PASSIVE3

VARI SKILL_CNT
VARI I
;アクティブスキルの抽選
;武器のアクティブスキルは最大2つ
CALL LIST_SHUFFLE(LIST_CANDIDATE_ACTIVE)
FOR I, 0, LIST_COUNT(LIST_CANDIDATE_ACTIVE)
    IF I >= 2 || SKILL_CNT >= 4 || !(RAND:100 < 60 + (TABLE_RANK * 10) - (I * 45))
        BREAK
    ENDIF
    LIST_RESULT_ACTIVE = %LIST_ADD(LIST_RESULT_ACTIVE, LIST_GET(LIST_CANDIDATE_ACTIVE, 0))%
    SKILL_CNT ++
NEXT

;パッシブスキルの抽選1 通常パッシブ
CALL LIST_SHUFFLE(LIST_CANDIDATE_PASSIVE1)
FOR I, 0, LIST_COUNT(LIST_CANDIDATE_PASSIVE1)
    IF I >= 2 || SKILL_CNT >= 4 || !(RAND:100 < 65 + (TABLE_RANK * 10) - (I * 45))
        BREAK
    ENDIF
    LIST_RESULT_PASSIVE1 = %LIST_ADD(LIST_RESULT_PASSIVE1, LIST_GET(LIST_CANDIDATE_PASSIVE1, I))%
    SKILL_CNT ++
NEXT

;パッシブスキルの抽選2 ステータスブースト
CALL LIST_SHUFFLE(LIST_CANDIDATE_PASSIVE2)
FOR I, 0, LIST_COUNT(LIST_CANDIDATE_PASSIVE2)
    IF I >= 2 || SKILL_CNT >= 4 || !(RAND:100 < 75 + (TABLE_RANK * 10) - (I * 40))
        BREAK
    ENDIF
    LIST_RESULT_PASSIVE2 = %LIST_ADD(LIST_RESULT_PASSIVE2, LIST_GET(LIST_CANDIDATE_PASSIVE2, I))%
    SKILL_CNT ++
NEXT

; ;パッシブスキルの抽選3 耐性ブースト
; CALL LIST_SHUFFLE(LIST_CANDIDATE_PASSIVE3)
; FOR I, 0, LIST_COUNT(LIST_CANDIDATE_PASSIVE3)
;     IF I >= 2 || SKILL_CNT >= 4 || (RAND:100 < 70 + (TABLE_RANK * 10) - (I * 40))
;         BREAK
;     ENDIF
;     LIST_RESULT_PASSIVE3 = %LIST_ADD(LIST_RESULT_PASSIVE3, LIST_GET(LIST_CANDIDATE_PASSIVE3, I))%
;     SKILL_CNT ++
; NEXT
LIST_RESULT_PASSIVE = %LIST_RESULT_PASSIVE1%%LIST_RESULT_PASSIVE2%%LIST_RESULT_PASSIVE3%

VARS SKILL_DEF_NAME
VARI MAX_SKILL_LV
VARI SKILL_LV
VARI SKILL_LV_RANGE
VARI LEVEL_TABLE
;抽選結果に基づくスキルの辞書を作成
;アクティブスキル
FOR I, 0, LIST_COUNT(LIST_RESULT_ACTIVE)
    SKILL_DEF_NAME = %LIST_GET(LIST_RESULT_ACTIVE, I)%
    CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_アクティブ)
    SIF RESULTS == ""
        CONTINUE
    MAX_SKILL_LV = TOINT(RESULTS)
    SKILL_LV_RANGE = MAX(MAX_SKILL_LV / 3, 1)
    CALL RAND_WT_INIT()
    CALL RAND_WT_SET(1, 75 - (TABLE_RANK * 25))
    CALL RAND_WT_SET(2, 25 + TABLE_RANK * 25)
    LEVEL_TABLE = RAND_WT_RESULT()
    SKILL_LV = LIMIT(RAND((LEVEL_TABLE - 1) * SKILL_LV_RANGE, LEVEL_TABLE * SKILL_LV_RANGE + 1), 1, MAX_SKILL_LV)
    DIC_WPN_ACTIVE = %DIC_SET(DIC_WPN_ACTIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
NEXT

;パッシブスキル
FOR I, 0, LIST_COUNT(LIST_RESULT_PASSIVE)
    SKILL_DEF_NAME = %LIST_GET(LIST_RESULT_PASSIVE, I)%
    CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_パッシブ)
    SIF RESULTS == ""
        CONTINUE
    MAX_SKILL_LV = TOINT(RESULTS)
    SKILL_LV_RANGE = MAX(MAX_SKILL_LV / 3, 1)
    CALL RAND_WT_INIT()
    CALL RAND_WT_SET(1, 95)
    CALL RAND_WT_SET(2, 5 + TABLE_RANK * 10)
    LEVEL_TABLE = RAND_WT_RESULT()
    SKILL_LV = LIMIT(RAND((LEVEL_TABLE - 1) * SKILL_LV_RANGE, LEVEL_TABLE * SKILL_LV_RANGE), 1, MAX_SKILL_LV)
    DIC_WPN_PASSIVE = %DIC_SET(DIC_WPN_PASSIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
NEXT

RESULTS:0 = %DIC_WPN_ACTIVE%
RESULTS:1 = %DIC_WPN_PASSIVE%

RETURN 1

;-------------------------------------------------
;;; 武器用のスキル抽選の候補リストを作成
;;; - RETURN
;;; RESULTS:0 アクティブスキル候補リスト
;;; RESULTS:1 パッシブスキル候補リスト
;;; RESULTS:2 パッシブスキル候補リスト(ステータスブースト)
;;; RESULTS:3 パッシブスキル候補リスト(耐性ブースト)
;-------------------------------------------------
@QST_RANDOM_LOOT_EQUIP_SKILL_GET_ROLL_CANDIDATE_LIST_WEAPON(EQUIP_CATEGORY, TABLE_RANK = 0)
#DIM EQUIP_CATEGORY
#DIM TABLE_RANK
#DIM IS_ACTIVE_SKILL

VARS LIST_CANDIDATE_ACTIVE
VARS LIST_CANDIDATE_PASSIVE1
VARS LIST_CANDIDATE_PASSIVE2
SELECTCASE EQUIP_CATEGORY
    CASE WPN_装備種類_短剣
        LIST_CANDIDATE_ACTIVE  += "WPN_FATAL_ATTACK," ;致命打
        LIST_CANDIDATE_ACTIVE  += "WPN_ADD_FRAGILE," ;穿孔
        LIST_CANDIDATE_PASSIVE1 += "WPN_UPWARD_ARMOR_DECAY," ;侵徹
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADDITIONAL_ATTACK," ;追撃
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_POISON," ;毒牙
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
    CASE WPN_装備種類_剣
        LIST_CANDIDATE_ACTIVE += "WPN_SMITE," ;重撃
        LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_POISON," ;毒牙
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
    CASE WPN_装備種類_斧
        LIST_CANDIDATE_ACTIVE += "WPN_SMITE," ;重撃
        LIST_CANDIDATE_ACTIVE  += "WPN_ADD_FRAGILE," ;穿孔
        LIST_CANDIDATE_PASSIVE1 += "WPN_UPWARD_ARMOR_DECAY," ;侵徹
        LIST_CANDIDATE_PASSIVE1 += "WPN_DEF_PENETRATE," ;貫通
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
    CASE WPN_装備種類_銃
        LIST_CANDIDATE_ACTIVE += "WPN_HARDSHOT," ;強装弾
        LIST_CANDIDATE_PASSIVE1 += "WPN_DEF_PENETRATE," ;貫通
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
    CASE WPN_装備種類_杖
        LIST_CANDIDATE_ACTIVE += "WPN_ADD_CAST_SELF," ;スペルブースト
        LIST_CANDIDATE_PASSIVE1 += "WPN_MAG_PENETRATE," ;魔防貫通
        LIST_CANDIDATE_PASSIVE2 += "WPN_MAG_BONUS," ;魔力＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_ATK_BONUS," ;攻撃＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT," ;心眼＋
        LIST_CANDIDATE_PASSIVE2 += "WPN_BOOST_CRT_DAMAGE," ;必殺＋
ENDSELECT

RESULTS:0 = %LIST_CANDIDATE_ACTIVE%
RESULTS:1 = %LIST_CANDIDATE_PASSIVE1%
RESULTS:2 = %LIST_CANDIDATE_PASSIVE2%
RETURN