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:{カラー_注意}@%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:{カラー_注意}@%LOCALS%:%WEAPON_NAME%を入手した@/C@", 1)
        CALLF TAG_PRINT(@"@C:{カラー_注意}@(※右クリック時入手)@/C@", 1)
        ;品質 = LIMIT(品質, 0, VARSIZE("WPN_品質") - 1 )
        ;CALLF TAG_PRINT(@"%LOCALS%:@C:{カラー_注釈}@*%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, "入手", "入手してお気に入り登録", "入手して陳列", "廃棄")
        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_PASSIVE1 += "WPN_ADD_PRAYER_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

repo_name: napo/erafl

license: unknown


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," ;ルーンプリローダ
    LIST_CANDIDATE_PASSIVE1 += "WPN_ADD_PRAYER_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


code:
;;; V0.360リリース以降にソース削除
;;; 以下のソースにて代替
;;; QST_RANDOM_EQUIP_LOOT_WEAPON()
;;; QST_RANDOM_EQUIP_LOOT_RELIC()
; ;-------------------------------------------------
; ; 汎用武器ガチャ
; ;-------------------------------------------------
; ;武器の抽選
; ; #region @QST_WEAPON_GACHA
; @QST_WEAPON_GACHA(TABLE_RANK = 0)
; #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()
; CALL RAND_WT_SET(WPN_材質_鉄, 50)
; CALL RAND_WT_SET(WPN_材質_鋼, 30)
; CALL RAND_WT_SET(WPN_材質_銀, 20)
; MATERIAL = RAND_WT_RESULT()

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

; ;スキル抽選
; CALL QST_WEAPON_GACHA_SKILL_PASSIVE(CATEGORY, TABLE_RANK)
; DIC_WPN_PASSIVE = %RESULTS%
; CALL QST_WEAPON_GACHA_SKILL_ACTIVE(CATEGORY, TABLE_RANK)
; DIC_WPN_ACTIVE = %RESULTS%

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

; CALL QST_GET_WEAPON(WEAPON_ID, WEAPON_NAME, MATERIAL, RANK, DIC_WPN_PASSIVE, DIC_WPN_ACTIVE)

; @QST_WEAPON_GACHA_SKILL_PASSIVE(CATEGORY, TABLE_RANK = 0)
; #DIMS CATEGORY
; #DIM  TABLE_RANK
; #DIMS DYNAMIC LIST_SKILL_LOTO_TARGET
; #DIMS DYNAMIC LIST_SKILL_LOTO_RESULT_PASSIVE
; #DIMS DYNAMIC LIST_SKILL_LOTO_RESULT_ACTIVE
; #DIMS DYNAMIC DIC_WPN_PASSIVE
; #DIMS DYNAMIC SKILL_DEF_NAME
; #DIM  DYNAMIC MAX_SKILL_LV
; #DIM  DYNAMIC SKILL_LV
; {
;     #DIMS CONST LIST_PASSIVE_SHORT_SWORD =
;         "WPN_UPWARD_ARMOR_DECAY"
;         ,"WPN_ADDITIONAL_ATTACK"
;         ,"WPN_ADD_POISON"
; }
; {
;     #DIMS CONST LIST_PASSIVE_LONG_SWORD =
;         "WPN_TRAMPLE"
;         ,"WPN_ADD_POISON"
; }
; {
;     #DIMS CONST LIST_PASSIVE_AXE =
;         "WPN_TRAMPLE"
;         ,"WPN_ADD_POISON"
; }

; VARSET RESULTS
; SIF !EXISTVAR(@"LIST_PASSIVE_%CATEGORY%")
;     RETURN 0

; ;武器スキル_パッシブ
; FOR LOCAL, 0, VARSIZE(@"LIST_PASSIVE_%CATEGORY%")
;     LIST_SKILL_LOTO_TARGET = %LIST_ADD(LIST_SKILL_LOTO_TARGET, GETVARS(@"LIST_PASSIVE_%CATEGORY%:{LOCAL}"))%
; NEXT
; CALL LIST_SHUFFLE(LIST_SKILL_LOTO_TARGET)
; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_TARGET)
;     SIF RAND(0, 100) < 75 - LOCAL * 45
;         BREAK
;     LIST_SKILL_LOTO_RESULT_PASSIVE = %LIST_ADD(LIST_SKILL_LOTO_RESULT_PASSIVE, LIST_GET(LIST_SKILL_LOTO_TARGET, LOCAL))%
; NEXT

; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_RESULT_PASSIVE)
;     SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_LOTO_RESULT_PASSIVE, LOCAL)%
;     CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_パッシブ)
;     SIF RESULTS == ""
;         CONTINUE
;     MAX_SKILL_LV = TOINT(RESULTS)
;     CALL RAND_WT_INIT()
;     CALL RAND_WT_SET(1, 75)
;     CALL RAND_WT_SET(2, 20)
;     CALL RAND_WT_SET(3, 5)
;     SKILL_LV = MIN(RAND_WT_RESULT(), MAX_SKILL_LV)
;     DIC_WPN_PASSIVE = %DIC_SET(DIC_WPN_PASSIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
; NEXT

; RESULTS = %DIC_WPN_PASSIVE%
; RETURN

; @QST_WEAPON_GACHA_SKILL_ACTIVE(CATEGORY, TABLE_RANK = 0)
; #DIMS CATEGORY
; #DIM  TABLE_RANK
; #DIMS DYNAMIC LIST_SKILL_LOTO_TARGET
; #DIMS DYNAMIC LIST_SKILL_LOTO_RESULT_ACTIVE
; #DIMS DYNAMIC DIC_WPN_ACTIVE
; #DIMS DYNAMIC SKILL_DEF_NAME
; #DIM  DYNAMIC MAX_SKILL_LV
; #DIM  DYNAMIC SKILL_LV
; {
;     #DIMS CONST LIST_ACTIVE_LONG_SWORD =
;         "WPN_SMITE"
; }
; {
;     #DIMS CONST LIST_ACTIVE_AXE =
;         "WPN_SMITE"
; }
; {
;     #DIMS CONST LIST_ACTIVE_GUN =
;         "WPN_HARDSHOT"
; }

; VARSET RESULTS
; SIF !EXISTVAR(@"LIST_ACTIVE_%CATEGORY%")
;     RETURN 0

; ;武器スキル_アクティブ
; FOR LOCAL, 0, VARSIZE(@"LIST_ACTIVE_%CATEGORY%")
;     LIST_SKILL_LOTO_TARGET = %LIST_ADD(LIST_SKILL_LOTO_TARGET, GETVARS(@"LIST_ACTIVE_%CATEGORY%:{LOCAL}"))%
; NEXT
; CALL LIST_SHUFFLE(LIST_SKILL_LOTO_TARGET)
; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_TARGET)
;     SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_LOTO_TARGET, LOCAL)%
;     ;武器種毎の確定枠
;     SELECTCASE CATEGORY
;         CASE "GUN"
;             IF SKILL_DEF_NAME == "WPN_HARDSHOT"
;                 LIST_SKILL_LOTO_RESULT_ACTIVE = %LIST_ADD(LIST_SKILL_LOTO_RESULT_ACTIVE, SKILL_DEF_NAME)%
;                 CONTINUE
;             ENDIF
;     ENDSELECT
;     ;抽選枠
;     SIF RAND(0, 100) < 75 - LOCAL * 45
;         BREAK
;     LIST_SKILL_LOTO_RESULT_ACTIVE = %LIST_ADD(LIST_SKILL_LOTO_RESULT_ACTIVE, SKILL_DEF_NAME)%
; NEXT

; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_RESULT_ACTIVE)
;     SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_LOTO_RESULT_ACTIVE, LOCAL)%
;     CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_アクティブ)
;     DEBUGPRINTFORML %SKILL_DEF_NAME%MAX_LV = %RESULTS%
;     SIF RESULTS == ""
;         CONTINUE
;     MAX_SKILL_LV = TOINT(RESULTS)
;     CALL RAND_WT_INIT()
;     CALL RAND_WT_SET(1, 75)
;     CALL RAND_WT_SET(2, 20)
;     CALL RAND_WT_SET(3, 5)
;     SKILL_LV = MIN(RAND_WT_RESULT(), MAX_SKILL_LV)
;     DIC_WPN_ACTIVE = %DIC_SET(DIC_WPN_ACTIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
; NEXT

; RESULTS = %DIC_WPN_ACTIVE%
; RETURN
; ; #endregion

; ;-------------------------------------------------
; ; 汎用レリックガチャ
; ;-------------------------------------------------
; ;武器の抽選
; ; #region @QST_WEAPON_GACHA
; @QST_RELIC_GACHA(TABLE_RANK = 0)
; #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)
; ENDSELECT

; ;スキル抽選
; CALL QST_RELIC_GACHA_SKILL_PASSIVE(CATEGORY, TABLE_RANK)
; DIC_WPN_PASSIVE = %RESULTS%
; CALL QST_RELIC_GACHA_SKILL_ACTIVE(CATEGORY, TABLE_RANK)
; DIC_WPN_ACTIVE = %RESULTS%

; ;武器名
; 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)

; @QST_RELIC_GACHA_SKILL_PASSIVE(CATEGORY, TABLE_RANK = 0)
; #DIMS CATEGORY
; #DIM  TABLE_RANK
; #DIMS DYNAMIC LIST_SKILL_LOTO_TARGET
; #DIMS DYNAMIC LIST_SKILL_LOTO_RESULT_PASSIVE
; #DIMS DYNAMIC LIST_SKILL_LOTO_RESULT_ACTIVE
; #DIMS DYNAMIC DIC_WPN_PASSIVE
; #DIMS DYNAMIC SKILL_DEF_NAME
; #DIM  DYNAMIC MAX_SKILL_LV
; #DIM  DYNAMIC SKILL_LV
; {
;     #DIMS CONST LIST_PASSIVE_BRACELET =
;         "WPN_UPWARD_ARMOR_DECAY"
;         ,"WPN_ADD_POISON"
; }
; {
;     #DIMS CONST LIST_PASSIVE_AMULET =
;         "WPN_ADD_SONG_AT_START"
;         ,"WPN_MAG_DEFENCE_UP"
; }
; {
;     #DIMS CONST LIST_PASSIVE_NECKLACE =
;         "WPN_DECOY_AMPLIFIER"
;         ,"WPN_MAG_DEFENCE_UP"
; }
; {
;     #DIMS CONST LIST_PASSIVE_BOOTS =
;         "WPN_TRAMPLE"
;         ,"WPN_ADDITIONAL_ATTACK"
; }
; {
;     #DIMS CONST LIST_PASSIVE_SHIELD =
;         "WPN_MAG_DEFENCE_UP"
; }
; {
;     #DIMS CONST LIST_PASSIVE_RING =
;         "WPN_ADD_CAST_AT_START"
; }
; {
;     #DIMS COST_LIST_PASSIVE_STATUS_BOOST_ATK =
;         "WPN_DEF_PENETRATE"
;         ,"WPN_MAG_PENETRATE"
;         ,"WPN_ATK_BONUS"
;         ,"WPN_MAG_BONUS"
; }
; {
;     #DIMS COST_LIST_PASSIVE_STATUS_BOOST_DEF =
;         "WPN_ARMOR_BONUS"
;         ,"WPN_BOOST_REGIST_STUN"
;         ,"WPN_BOOST_REGIST_POISON"
;         ,"WPN_BOOST_REGIST_BURN"
; }

; VARSET RESULTS
; SIF !EXISTVAR(@"LIST_PASSIVE_%CATEGORY%")
;     RETURN 0

; ;武器スキル_パッシブ
; FOR LOCAL, 0, VARSIZE(@"LIST_PASSIVE_%CATEGORY%")
;     LIST_SKILL_LOTO_TARGET = %LIST_ADD(LIST_SKILL_LOTO_TARGET, GETVARS(@"LIST_PASSIVE_%CATEGORY%:{LOCAL}"))%
; NEXT
; CALL LIST_SHUFFLE(LIST_SKILL_LOTO_TARGET)
; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_TARGET)
;     SIF RAND(0, 100) < 75 - LOCAL * 45
;         BREAK
;     LIST_SKILL_LOTO_RESULT_PASSIVE = %LIST_ADD(LIST_SKILL_LOTO_RESULT_PASSIVE, LIST_GET(LIST_SKILL_LOTO_TARGET, LOCAL))%
; NEXT

; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_RESULT_PASSIVE)
;     SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_LOTO_RESULT_PASSIVE, LOCAL)%
;     CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_パッシブ)
;     SIF RESULTS == ""
;         CONTINUE
;     MAX_SKILL_LV = TOINT(RESULTS)
;     CALL RAND_WT_INIT()
;     CALL RAND_WT_SET(1, 95)
;     CALL RAND_WT_SET(2, 5)
;     SKILL_LV = MIN(RAND_WT_RESULT(), MAX_SKILL_LV)
;     DIC_WPN_PASSIVE = %DIC_SET(DIC_WPN_PASSIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
; NEXT

; RESULTS = %DIC_WPN_PASSIVE%
; RETURN

; @QST_RELIC_GACHA_SKILL_ACTIVE(CATEGORY, TABLE_RANK = 0)
; #DIMS CATEGORY
; #DIM  TABLE_RANK
; #DIMS DYNAMIC LIST_SKILL_LOTO_TARGET
; #DIMS DYNAMIC LIST_SKILL_LOTO_RESULT_ACTIVE
; #DIMS DYNAMIC DIC_WPN_ACTIVE
; #DIMS DYNAMIC SKILL_DEF_NAME
; #DIM  DYNAMIC MAX_SKILL_LV
; #DIM  DYNAMIC SKILL_LV
; {
;     #DIMS CONST LIST_ACTIVE_BRACELET =
;         "WPN_RECOVER_STUN_ALL"
;         ,"WPN_ADD_FRAGILE"
; }
; {
;     #DIMS CONST LIST_ACTIVE_AMULET =
;         "WPN_ADD_CAST_SELF"
;         ,"WPN_MAG_DEFENCE_UP"
; }
; {
;     #DIMS CONST LIST_ACTIVE_NECKLACE =
;         "WPN_RECOVER_STUN_ALL"
;         ,"WPN_ADD_MAG_GUARD"
; }
; ; {
; ;     #DIMS CONST LIST_ACTIVE_BOOTS =
; ;         ""
; ; }
; {
;     #DIMS CONST LIST_ACTIVE_SHIELD =
;         "WPN_ADD_MAG_GUARD"
;         ,"WPN_FRONT_DEFENCE"
; }
; {
;     #DIMS CONST LIST_ACTIVE_RING =
;         "WPN_ADD_CAST_SELF"
; }

; VARSET RESULTS
; SIF !EXISTVAR(@"LIST_ACTIVE_%CATEGORY%")
;     RETURN 0

; ;武器スキル_アクティブ
; FOR LOCAL, 0, VARSIZE(@"LIST_ACTIVE_%CATEGORY%")
;     LIST_SKILL_LOTO_TARGET = %LIST_ADD(LIST_SKILL_LOTO_TARGET, GETVARS(@"LIST_ACTIVE_%CATEGORY%:{LOCAL}"))%
; NEXT
; CALL LIST_SHUFFLE(LIST_SKILL_LOTO_TARGET)
; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_TARGET)
;     SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_LOTO_TARGET, LOCAL)%
;     ; ;武器種毎の確定枠
;     ; SELECTCASE CATEGORY
;     ;     CASE "GUN"
;     ;         IF SKILL_DEF_NAME == "WPN_HARDSHOT"
;     ;             LIST_SKILL_LOTO_RESULT_ACTIVE = %LIST_ADD(LIST_SKILL_LOTO_RESULT_ACTIVE, SKILL_DEF_NAME)%
;     ;             CONTINUE
;     ;         ENDIF
;     ; ENDSELECT
;     ;抽選枠
;     SIF RAND(0, 100) < 75 - LOCAL * 45
;         BREAK
;     LIST_SKILL_LOTO_RESULT_ACTIVE = %LIST_ADD(LIST_SKILL_LOTO_RESULT_ACTIVE, SKILL_DEF_NAME)%
; NEXT

; FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_LOTO_RESULT_ACTIVE)
;     SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_LOTO_RESULT_ACTIVE, LOCAL)%
;     CALLF GET_SKILL_DATA(SKILL_DEF_NAME, "maxlv", 1, 武器スキル_アクティブ)
;     DEBUGPRINTFORML %SKILL_DEF_NAME%MAX_LV = %RESULTS%
;     SIF RESULTS == ""
;         CONTINUE
;     MAX_SKILL_LV = TOINT(RESULTS)
;     CALL RAND_WT_INIT()
;     CALL RAND_WT_SET(1, 95)
;     CALL RAND_WT_SET(2, 5)
;     ;CALL RAND_WT_SET(3, 5)
;     SKILL_LV = MIN(RAND_WT_RESULT(), MAX_SKILL_LV)
;     DIC_WPN_ACTIVE = %DIC_SET(DIC_WPN_ACTIVE, SKILL_DEF_NAME, TOSTR(SKILL_LV))%
; NEXT

; RESULTS = %DIC_WPN_ACTIVE%
; RETURN
; ; #endregion


code:
;-------------------------------------------------
;クエストモードでは未探索のルーム情報を伏せる
;-------------------------------------------------
@QST_SET_FOG_OF_WAR(ROOM_IDX = -1)
#DIM ROOM_IDX
IF ROOM_IDX == -1
    FOR LOCAL, 0, HO_MAX_ROOMNUM
        CALL HO_SET_MAPDATA(LOCAL, "FOG_OF_WAR", "1")
    NEXT
ELSE
    CALL HO_SET_MAPDATA(ROOM_IDX, "FOG_OF_WAR", "1")
ENDIF

;対象ROOM_IDXの戦場の霧を晴らす
;ARG:1が0以外の場合、隣接するルームも晴らす
;マップデータ定義で[IS_HIDDEN_ROOM:1]が指定されている場合は隣接ルーム晴らしから除外
@QST_CLEAR_FOG_OF_WAR(ROOM_IDX, 対象のみ = 0)
#DIM ROOM_IDX
#DIM 対象のみ
#DIMS DYNAMIC _LIST_ROOM_PATH
CALL HO_GET_PATH(ROOM_IDX)
_LIST_ROOM_PATH = %RESULTS%
CALL HO_SET_MAPDATA(ROOM_IDX, "FOG_OF_WAR", "0")
IF !対象のみ
    FOR LOCAL, 0, LIST_COUNT(_LIST_ROOM_PATH)
        CALL HO_GET_MAPDATA(HO_有効マップID, TOINT(LIST_GET(_LIST_ROOM_PATH, LOCAL)), "IS_HIDDEN_ROOM")
        SIF RESULT == 1
            CONTINUE
        CALL HO_SET_MAPDATA(TOINT(LIST_GET(_LIST_ROOM_PATH, LOCAL)), "FOG_OF_WAR", "0")
    NEXT
ENDIF

;-------------------------------------------------
;クエストの探索状態を保持する
;-------------------------------------------------
;探索済ルームの情報を開示
@QST_EXPLORED_ROOMS_DISCLOSURE()
#DIM  DYNAMIC QUEST_ID

QUEST_ID = QST_有効クエストID

;探索状態を保持しないクエスト中は追加しない
IF !QST_SAVE_EXPLORED
    RETURN
ENDIF

;デバッグ用表示:ルームIDXを表示
DEBUGPRINTL 探索済ルームIDX

;探索済ルームリストに設定されているルームの霧を晴らす
CALL LIST_FOREACH(QST_LIST_EXPLORED_ROOM:QUEST_ID, "QST_LIST_EXPLORED_ROOM_FOREACH_CLEAR_FOG_ROOM")

;-------------------------------------------------
;探索済ルームリストに設定されているルームの霧を晴らす(LIST_FOREACH用関数)
@QST_LIST_EXPLORED_ROOM_FOREACH_CLEAR_FOG_ROOM(STR_ROOM_IDX)
#DIMS STR_ROOM_IDX
;デバッグ用表示:ルームIDXを表示
DEBUGPRINTFORM %STR_ROOM_IDX%,
;霧を晴らす
CALL QST_CLEAR_FOG_OF_WAR(TOINT(STR_ROOM_IDX))

;-------------------------------------------------
;クエストの探索状態保持設定の取得
@QST_GET_QST_SAVE_EXPLORED()
#DIM DYNAMIC QUEST_ID

QUEST_ID = QST_有効クエストID

;クエストごとの探索状態保持設定の関数をチェック
TRYCCALLFORM QST_QUEST_{QUEST_ID}_SAVE_EXPLORED()
    QST_SAVE_EXPLORED = RESULT
    DEBUGPRINTFORML FUNCTION "QST_QUEST_{QUEST_ID}_SAVE_EXPLORED" EXIST
    DEBUGPRINTFORML QST_SAVE_EXPLORED: {QST_SAVE_EXPLORED}
CATCH
    ;関数がない場合は探索状態を保持しない
    QST_SAVE_EXPLORED = 0
    DEBUGPRINTFORML FUNCTION "QST_QUEST_{QUEST_ID}_SAVE_EXPLORED" NOT EXIST
ENDCATCH

;-------------------------------------------------
;探索済ルームをリストに追加
@QST_ADD_LIST_EXPLORED_ROOM(ROOM_IDX, FORCED = 0)
#DIM  ROOM_IDX
#DIM  FORCED
#DIMS DYNAMIC STR_ROOM_IDX
#DIM  DYNAMIC QUEST_ID
#DIM  DYNAMIC NOT_SAVE_EXPLORED
#DIM  DYNAMIC MAP_ID

QUEST_ID = QST_有効クエストID
MAP_ID   = HO_有効マップID
STR_ROOM_IDX '= TOSTR(ROOM_IDX)

;探索状態を保持しないクエスト中は追加しない
IF !QST_SAVE_EXPLORED
    RETURN
ENDIF

;「探索状態を保持しない」設定がされているルームは追加しない
;・設定がされていない(0:設定なし, -1:未定義)ルームは追加する
;・強制設定フラグがONの場合はルーム設定を無視して追加する
IF !FORCED
    CALL HO_GET_MAPDATA(MAP_ID, ROOM_IDX, "NOT_SAVE_EXPLORED")
    NOT_SAVE_EXPLORED = RESULT
    IF !GROUPMATCH(NOT_SAVE_EXPLORED , 0, -1)
        RETURN
    ENDIF
ENDIF

;既に探索済ルームリストに追加済の場合は追加しない(重複追加防止)
IF LIST_INDEXOF(QST_LIST_EXPLORED_ROOM:QUEST_ID, STR_ROOM_IDX) != -1
    RETURN
ENDIF

;探索済ルームリストにルームIDXを追加
QST_LIST_EXPLORED_ROOM:QUEST_ID '= LIST_ADD(QST_LIST_EXPLORED_ROOM:QUEST_ID, STR_ROOM_IDX)

;-------------------------------------------------
;探索済ルームをリストから削除
@QST_REMOVE_LIST_EXPLORED_ROOM(ROOM_IDX)
#DIM  ROOM_IDX
#DIMS DYNAMIC STR_ROOM_IDX
#DIM  DYNAMIC QUEST_ID

QUEST_ID = QST_有効クエストID
STR_ROOM_IDX '= TOSTR(ROOM_IDX)

QST_LIST_EXPLORED_ROOM:QUEST_ID '= LIST_REMOVEALL(QST_LIST_EXPLORED_ROOM:QUEST_ID, STR_ROOM_IDX)

;-------------------------------------------------
;探索済ルームリストの件数を取得
@QST_GET_LIST_EXPLORED_ROOM_COUNT()
#FUNCTION
#DIM  DYNAMIC QUEST_ID

QUEST_ID = QST_有効クエストID

RETURNF LIST_COUNT(QST_LIST_EXPLORED_ROOM:QUEST_ID)

;-------------------------------------------------
;ルーム設定「探索状態を保持しない」
;-------------------------------------------------
@QST_SET_ROOM_NOT_SAVE_EXPLORED(ROOM_IDX = -1)
#DIM ROOM_IDX
CALL HO_SET_MAPDATA(ROOM_IDX, "NOT_SAVE_EXPLORED", "1")

@QST_CLEAR_ROOM_NOT_SAVE_EXPLORED(ROOM_IDX = -1)
#DIM ROOM_IDX
CALL HO_SET_MAPDATA(ROOM_IDX, "NOT_SAVE_EXPLORED", "0")

;-------------------------------------------------
;クエスト用コンパニオン追加関数
;-------------------------------------------------
@QST_ADD_COMPANION(CHARA_ID)
#DIM CHARA_ID
#DIMS DYNAMIC _LIST_COMPANION

VARSET RESULTS

SIF CHARA_ID == MASTER
    RETURN 0

CFLAG:CHARA_ID:調教参加フラグ = 1
TFLAG:参加者数 ++
CALL HO_SET_CHARAACT(CHARA_ID, "同行中")

;リストの管理
CALL HO_GET_MASTER_DATA("COMPANION_LIST")
_LIST_COMPANION = %RESULTS%
IF LIST_INDEXOF(_LIST_COMPANION, TOSTR(CHARA_ID)) == -1
    _LIST_COMPANION = %LIST_ADD(_LIST_COMPANION, TOSTR(CHARA_ID))%
    CALL HO_SET_MASTER_DATA("COMPANION_LIST", _LIST_COMPANION)
ELSE
    THROW 同一キャラを多重に登録しようとしました CHARA_ID{CHARA_ID}
ENDIF
;広域変数のパーティリストに対象を追加
;_LIST_QST_PARTY = %LIST_ADD(_LIST_QST_PARTY, TOSTR(CHARA_ID))%
RETURN 1

;-------------------------------------------------
;入室時に自動実行されるタイプのイベントを呼び出す
@QST_EXEC_ENTER_EVENT(ROOM_IDX)
#DIM ROOM_IDX
#DIM  DYNAMIC EVENT_ROOM_IDX
#DIM  DYNAMIC EVENT_LIST_IDX
#DIMS DYNAMIC _LIST_EVENT_LIST
#DIMS DYNAMIC EVENT_TRIGGER
#DIMS DYNAMIC EVENT_TYPE
#DIM DYNAMIC  IS_EVENT_EXECUTED
#DIMS DYNAMIC EVENT_STATE

FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "ROOM_IDX")
    EVENT_ROOM_IDX = RESULT
    IF ROOM_IDX == EVENT_ROOM_IDX
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_TRIGGER")
        EVENT_TRIGGER = %RESULTS%

        IF EVENT_TRIGGER == "ENTER_ROOM" || EVENT_TRIGGER == "COLIDE_PLAYER"
            ;EVENT_TYPEが"ONCE"かつ実行済みのイベントは実行しない
            CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_TYPE")
            EVENT_TYPE = %RESULTS%
            CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "IS_EVENT_EXECUTED")
            IS_EVENT_EXECUTED = RESULT
            CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_STATE")
            EVENT_STATE = %RESULTS%
            SIF (EVENT_TYPE == "ONCE" && IS_EVENT_EXECUTED == 1) || EVENT_STATE == "DEACTIVE"
                RETURN
            CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
            PRINTL
            QST_NOWEV_LIST_IDX = EVENT_LIST_IDX
            QST_NOWEV = RESULT
            TRYCCALLFORM  QST_QUEST_{QST_有効クエストID}_EVENT_{QST_NOWEV}
                CALL QST_SET_EVENT_LIST(EVENT_LIST_IDX, "IS_EVENT_EXECUTED", "1")
            CATCH
                QST_NOWEV_LIST_IDX = -1
            ENDCATCH
        ENDIF
    ENDIF
NEXT

CALL QST_EVENTEND()

@QST_EXEC_EVENT_PAWN_COLIDE(ROOM_IDX, EVENT_LIST_IDX)
#DIM  ROOM_IDX
#DIM  EVENT_LIST_IDX
#DIM  DYNAMIC EVENT_ROOM_IDX
#DIMS DYNAMIC _LIST_EVENT_LIST
#DIMS DYNAMIC EVENT_TRIGGER
#DIMS DYNAMIC EVENT_TYPE
#DIM DYNAMIC  IS_EVENT_EXECUTED
#DIMS DYNAMIC EVENT_STATE

CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "ROOM_IDX")
EVENT_ROOM_IDX = RESULT
IF ROOM_IDX == EVENT_ROOM_IDX
    CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_TRIGGER")
    EVENT_TRIGGER = %RESULTS%

    IF EVENT_TRIGGER == "COLIDE_PLAYER"
        ;EVENT_TYPEが"ONCE"かつ実行済みのイベントは実行しない
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_TYPE")
        EVENT_TYPE = %RESULTS%
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "IS_EVENT_EXECUTED")
        IS_EVENT_EXECUTED = RESULT
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_STATE")
        EVENT_STATE = %RESULTS%
        SIF (EVENT_TYPE == "ONCE" && IS_EVENT_EXECUTED == 1) || EVENT_STATE == "DEACTIVE"
            RETURN
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
        PRINTL
        QST_NOWEV_LIST_IDX = EVENT_LIST_IDX
        QST_NOWEV = RESULT
        TRYCCALLFORM  QST_QUEST_{QST_有効クエストID}_EVENT_{QST_NOWEV}
            CALL QST_SET_EVENT_LIST(EVENT_LIST_IDX, "IS_EVENT_EXECUTED", "1")
        CATCH
            QST_NOWEV_LIST_IDX = -1
        ENDCATCH
    ENDIF
ENDIF

CALL QST_EVENTEND()

;-------------------------------------------------
;イベントスロットのボタンクリック時に呼び出されるイベントを呼び出す
@QST_EXEC_EVENT_SLOT_EVENT(EVENT_LIST_IDX)
#DIM  DYNAMIC EVENT_LIST_IDX
#DIMS DYNAMIC _LIST_EVENT_LIST

QST_NOWEV_LIST_IDX = EVENT_LIST_IDX
CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
QST_NOWEV = RESULT
PRINTL
TRYCALLFORM QST_QUEST_{QST_有効クエストID}_EVENT_{QST_NOWEV}

CALL QST_EVENTEND()
;全滅したか、スロットイベントが調教イベントを起動した場合、コモンイベントの呼び出しは実施しない
IF RESULT || FLAG:ウフフフラグ
    RETURN
ENDIF
CALL QST_EVENT_汎用イベント

;-------------------------------------------------
;イベントリスト管理関数
;-------------------------------------------------
@QST_SET_EVENT_LIST(EVENT_LIST_IDX, DATANAME, VALUES, MAP_ID = -1)
#DIM  EVENT_LIST_IDX
#DIMS DATANAME
#DIMS VALUES
#DIM  MAP_ID

SIF MAP_ID == -1
    MAP_ID = HO_有効マップID
SIF _DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX == "-1"
    _DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX '= ""

_DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX = %DIC_SET(_DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX, DATANAME, VALUES)%
RETURN

@QST_GET_EVENT_LIST(EVENT_LIST_IDX, DATANAME, MAP_ID = -1)
#DIM MAP_ID
#DIM EVENT_LIST_IDX
#DIM ROOM_IDX
#DIMS DATANAME

SIF MAP_ID == -1
    MAP_ID = HO_有効マップID

VARSET RESULTS
SIF DIC_GET(_DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX, DATANAME) == ""
    RETURN -1

ISNUMERIC DIC_GET(_DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX, DATANAME)
IF RESULT
    RETURN TOINT(DIC_GET(_DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX, DATANAME))
ELSE
    RESULTS = %DIC_GET(_DIC_QST_EVENT_LIST:MAP_ID:EVENT_LIST_IDX, DATANAME)%
    RETURN
ENDIF

;-------------------------------------------------
;イベントリストに登録されたイベントのフラグ管理
;-------------------------------------------------
@QST_SET_EVENT_FLAG(EVENT_ID, VALUE)
#DIM EVENT_ID
#DIM VALUE
#DIM  DYNAMIC EVENT_LIST_IDX
#DIM  DYNAMIC TARGET_EVENT_ID
#DIMS DYNAMIC _LIST_EVENT_LIST
FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
    TARGET_EVENT_ID = RESULT
    IF EVENT_ID == TARGET_EVENT_ID
        CALL QST_SET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_FLAG", TOSTR(VALUE))
        RETURN 1
    ENDIF
NEXT
RETURN 0

@QST_GET_EVENT_FLAG(EVENT_ID)
#DIM EVENT_ID
#DIM VALUE
#DIM  DYNAMIC EVENT_LIST_IDX
#DIM  DYNAMIC TARGET_EVENT_ID
#DIMS DYNAMIC _LIST_EVENT_LIST
FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
    TARGET_EVENT_ID = RESULT
    IF EVENT_ID == TARGET_EVENT_ID
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_FLAG")
        SIF RESULT == -1
            RESULT = 0
        RETURN RESULT
    ENDIF
NEXT
RETURN 0

;EVENT_IDではイベントを一意に識別できない場合、こちらを使用する
;QST_NOWEV_LIST_IDXはイベント実行直前にセットされる
@QST_SET_EVENT_FLAG_BY_IDX(VALUE)
#DIM VALUE
SIF VALUE == -1
    RETURN 0
CALL QST_SET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_FLAG", TOSTR(VALUE))
RETURN 1

@QST_GET_EVENT_FLAG_BY_IDX()
CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_FLAG")
SIF RESULT == -1
    RETURN 0
RETURN RESULT

;セーブデータに保持されるフラグ管理変数
@QST_SET_SV_EVENT_FLAG(EVENT_ID, VALUE)
#DIM EVENT_ID
#DIM VALUE
QST_SV_EVENT_FLAG:QST_有効クエストID:EVENT_ID = VALUE
RETURN

@QST_GET_SV_EVENT_FLAG(EVENT_ID)
#DIM EVENT_ID
RETURN QST_SV_EVENT_FLAG:QST_有効クエストID:EVENT_ID

;式中関数版
@QST_GET_SV_EVENT_FLAGF(EVENT_ID)
#FUNCTION
#DIM EVENT_ID
RETURNF QST_SV_EVENT_FLAG:QST_有効クエストID:EVENT_ID

;-------------------------------------------------
;;; フラグ連想配列管理用
;;; 実行中のクエスト専用のフラグ連想配列に任意のキー：値のペアを格納できる
;;; 呼び出しは @QST_GET_FLAGMAPを使用する
;;; クエスト終了時に初期化される点に注意
;;;
;;; 【特殊なフラグ】
;;; 以下の固定キーに値をセットすると、特定のタイミングで所定の処理が実行される
;;;
;;; - EVENTCOMEND_CALLEE
;;; 値をセットすると、コマンド実行時に毎回値に指定した関数が呼び出される
;;; ※呼び出し不要となった場合は明示的に値をクリアすること
;;;
;;; - EVENTCOMEND_CALLEE_ONCE
;;; 値をセットすると、コマンド実行時に一度だけ指定した関数が呼び出される
;;; ※呼び出し後に自動的にクリアされるため、明示的なクリアは不要
;;;
;;; - TRAIN_EXIT_CALLEE
;;; 値をセットすると、調教終了時にその値に対応した関数が呼び出される
;;; ※呼び出し後に自動的にクリアされるため、明示的なクリアは不要
;;;
;-------------------------------------------------
@QST_SET_FLAGMAP(KEYS, VALUES)
#DIMS KEYS
#DIMS VALUES
MAP_SET @"QUEST_{QST_有効クエストID}_MAP", KEYS, VALUES

;;; 数値をフラグ変数にセット
@QST_SETINT_FLAGMAP(KEYS, VALUE)
#DIMS KEYS
#DIM  VALUE
CALL QST_SET_FLAGMAP(KEYS, TOSTR(VALUE))

;;; 数値をフラグ変数に加算
@QST_ADDINT_FLAGMAP(KEYS, ADD_VALUE)
#DIMS KEYS
#DIM  ADD_VALUE
#DIM  CURRENT_VALUE

CURRENT_VALUE = QST_GETINT_FLAGMAP(KEYS)
CALL QST_SETINT_FLAGMAP(KEYS, CURRENT_VALUE + ADD_VALUE)

;;; @QST_SET_FLAGMAPでセットしたフラグ変数を取得する
@QST_GET_FLAGMAP(KEYS)
#FUNCTIONS
#DIMS KEYS
RETURNF MAP_GET(@"QUEST_{QST_有効クエストID}_MAP", KEYS)

;;; @QST_SET_FLAGMAPでセットしたフラグ変数を数値変換して取得する
@QST_GETINT_FLAGMAP(KEYS)
#FUNCTION
#DIMS KEYS
RETURNF TOINT(QST_GET_FLAGMAP(KEYS))

;;; @QST_SET_FLAGMAPでセットしたフラグ変数を削除する
@QST_REMOVE_FLAGMAP(KEYS)
#DIMS KEYS
MAP_REMOVE @"QUEST_{QST_有効クエストID}_MAP", KEYS

;-------------------------------------------------
;イベントの活性、非活性
;-------------------------------------------------
@QST_ACTIVATE_EVENT(EVENT_ID)
#DIM EVENT_ID
#DIM VALUE
#DIM  DYNAMIC EVENT_LIST_IDX
#DIM  DYNAMIC TARGET_EVENT_ID
#DIMS DYNAMIC _LIST_EVENT_LIST
FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
    TARGET_EVENT_ID = RESULT
    IF EVENT_ID == TARGET_EVENT_ID
        CALL QST_SET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_STATE", "ACTIVE")
        RETURN 1
    ENDIF
NEXT
RETURN 0

;-------------------------------------------------
;;; イベント非活性化
;;; ※QST_ADD_EVENT_QUEST_XX_EVENT_XXから呼び出した場合は
;;; 呼び出し元イベントIDのみ非活性化可能(指定先EVENT_IDの登録状況を保証出来ないため)
;-------------------------------------------------
@QST_DEACTIVATE_EVENT(EVENT_ID)
#DIM EVENT_ID
#DIM VALUE
#DIM  DYNAMIC EVENT_LIST_IDX
#DIM  DYNAMIC TARGET_EVENT_ID
#DIMS DYNAMIC _LIST_EVENT_LIST
FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
    CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
    TARGET_EVENT_ID = RESULT
    IF EVENT_ID == TARGET_EVENT_ID
        CALL QST_SET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_STATE", "DEACTIVE")
        RETURN 1
    ENDIF
NEXT
RETURN 0

@QST_DEACTIVATE_THIS_EVENT()
CALL QST_SET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_STATE", "DEACTIVE")

;-------------------------------------------------
;イベントスロット上に表示するイベント名を変更する
;EVENT_IDが未指定の場合、現在実行しているイベントの名称を変更する
;-------------------------------------------------
@QST_SET_EVENT_SLOT_NAME(EVENT_ID = -1, EVENT_SLOT_NAME)
#DIM EVENT_ID
#DIMS EVENT_SLOT_NAME
#DIM  DYNAMIC EVENT_LIST_IDX
#DIM  DYNAMIC TARGET_EVENT_ID
#DIMS DYNAMIC _LIST_EVENT_LIST
IF EVENT_ID != -1
    FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
        TARGET_EVENT_ID = RESULT
        IF EVENT_ID == TARGET_EVENT_ID
            CALL QST_SET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_SLOT_NAME", EVENT_SLOT_NAME)
            RETURN 1
        ENDIF
    NEXT
ELSE
    CALL QST_SET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_SLOT_NAME", EVENT_SLOT_NAME)
ENDIF
RETURN 0

;現在設定されているイベント名を取得
@QST_GET_EVENT_SLOT_NAME(EVENT_ID = -1)
#DIM EVENT_ID
#DIM  DYNAMIC EVENT_LIST_IDX
#DIM  DYNAMIC TARGET_EVENT_ID
#DIMS DYNAMIC _LIST_EVENT_LIST
IF EVENT_ID != -1
    FOR EVENT_LIST_IDX, 0, QST_MAX_EVENTNUM
        CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_ID")
        TARGET_EVENT_ID = RESULT
        IF EVENT_ID == TARGET_EVENT_ID
            CALL QST_GET_EVENT_LIST(EVENT_LIST_IDX, "EVENT_SLOT_NAME")
            RETURN 1
        ENDIF
    NEXT
ELSE
    CALL QST_GET_EVENT_LIST(QST_NOWEV_LIST_IDX, "EVENT_SLOT_NAME")
ENDIF
RETURN 0

;-------------------------------------------------
;調教終了後イベント呼出用リスト管理
;-------------------------------------------------
@QST_ENQUEUE_TRAIN_EXIT_EVENT(EVENT_ID)
#DIM EVENT_ID
_LIST_QST_TRAIN_EXIT_EVENT = %LIST_ADD(_LIST_QST_TRAIN_EXIT_EVENT, TOSTR(EVENT_ID))%

@QST_ENQUEUE_TRAIN_EXIT_FUNC(FUNCTION_NAME)
#DIMS FUNCTION_NAME
_LIST_QST_TRAIN_EXIT_EVENT = %LIST_ADD(_LIST_QST_TRAIN_EXIT_EVENT, FUNCTION_NAME)%

@QST_DEQUEUE_TRAIN_EXIT_EVENT()
#DIM DYNAMIC EVENT_ID

VARSET RESULTS
SIF LIST_COUNT(_LIST_QST_TRAIN_EXIT_EVENT) == 0
    RETURN -1
;数値がセットされていた場合はEVENT_IDとして返す
IF TOINT(LIST_GET(_LIST_QST_TRAIN_EXIT_EVENT, 0))
    EVENT_ID = TOINT(LIST_GET(_LIST_QST_TRAIN_EXIT_EVENT, 0))
    _LIST_QST_TRAIN_EXIT_EVENT = %LIST_REMOVEAT(_LIST_QST_TRAIN_EXIT_EVENT, 0)%

    RETURN EVENT_ID
ELSE
    ;文字列がセットされていた場合はRESULTSにセットして1を返す
    RESULTS = %LIST_GET(_LIST_QST_TRAIN_EXIT_EVENT, 0)%
    _LIST_QST_TRAIN_EXIT_EVENT = %LIST_REMOVEAT(_LIST_QST_TRAIN_EXIT_EVENT, 0)%
    RETURN 1
ENDIF

;-------------------------------------------------
;;; 指定したマップ画像に変更する
;;; GMAPタイプのクエストのみ有効。指定する画像は RESOURCES/MAPIMAGE/ に予め配置すること
;-------------------------------------------------
@QST_CHANGE_MAP_IMAGE(SPRITE_NAME)
#DIMS SPRITE_NAME
CALL スプライト生成(@"mapimage/%SPRITE_NAME%", SPRITE_NAME)
ME_mapImage = %SPRITE_NAME%
RETURN

;-------------------------------------------------
;;; 指定したエリア間にパスを追加する
;-------------------------------------------------
@QST_ADD_PATH(ROOM_FROM, ROOM_TO)
#DIM  ROOM_FROM
#DIM  ROOM_TO
#DIM  ROOM_IDX_TEMP
#DIMS LIST_PATH

;若い番号のエリアから順に処理
IF ROOM_FROM > ROOM_TO
    ROOM_IDX_TEMP = ROOM_FROM
    ROOM_FROM = ROOM_TO
    ROOM_TO = ROOM_IDX_TEMP
ENDIF

CALL HO_GET_MAPDATA(HO_有効マップID, ROOM_FROM, "ROOM_PATH")
LIST_PATH = %RESULTS%
IF LIST_INDEXOF(LIST_PATH, TOSTR(ROOM_TO)) == -1
    LIST_PATH = %LIST_ADD(LIST_PATH, TOSTR(ROOM_TO))%
ENDIF
CALL HO_SET_MAPDATA(ROOM_FROM, "ROOM_PATH", LIST_PATH)

CALL HO_GET_MAPDATA(HO_有効マップID, ROOM_TO, "ROOM_PATH")
LIST_PATH = %RESULTS%
IF LIST_INDEXOF(LIST_PATH, TOSTR(ROOM_FROM)) == -1
    LIST_PATH = %LIST_ADD(LIST_PATH, TOSTR(ROOM_FROM))%
ENDIF
CALL HO_SET_MAPDATA(ROOM_TO, "ROOM_PATH", LIST_PATH)

;-------------------------------------------------
;;; 指定したエリア間のパスを削除する
;-------------------------------------------------
@QST_REMOVE_PATH(ROOM_FROM, ROOM_TO)
#DIM  ROOM_FROM
#DIM  ROOM_TO
#DIM  ROOM_IDX_TEMP
#DIMS LIST_PATH

;若い番号のエリアから順に処理
IF ROOM_FROM > ROOM_TO
    ROOM_IDX_TEMP = ROOM_FROM
    ROOM_FROM = ROOM_TO
    ROOM_TO = ROOM_IDX_TEMP
ENDIF

CALL HO_GET_MAPDATA(HO_有効マップID, ROOM_FROM, "ROOM_PATH")
LIST_PATH = %RESULTS%
IF LIST_INDEXOF(LIST_PATH, TOSTR(ROOM_TO)) != -1
    LIST_PATH = %LIST_REMOVEALL(LIST_PATH, TOSTR(ROOM_TO))%
ENDIF
CALL HO_SET_MAPDATA(ROOM_FROM, "ROOM_PATH", LIST_PATH)

CALL HO_GET_MAPDATA(HO_有効マップID, ROOM_TO, "ROOM_PATH")
LIST_PATH = %RESULTS%
IF LIST_INDEXOF(LIST_PATH, TOSTR(ROOM_FROM)) != -1
    LIST_PATH = %LIST_REMOVEALL(LIST_PATH, TOSTR(ROOM_FROM))%
ENDIF
CALL HO_SET_MAPDATA(ROOM_TO, "ROOM_PATH", LIST_PATH)