code:
;-------------------------------------------------
;戦闘処理
;予め"CC_ATTACKER_LIST", "CC_DEFENDER_LIST"のリスト(連想配列)に指定されたメンバーにて戦闘を実施する
; 戻り値 1 = "ATTACKER"勝利, 2 = "DEFENDER"勝利
;
;イベント実行例
; CALL CC_INIT()                                  ;参加メンバーリストを初期化
; CALL CC_ADDCHARA("ATTACKER", MASTER)                   ;攻撃側に"あなた"を指定
; CALL CC_ADDMOB("DEFENDER", "モブ", 1200, 1200, 15)     ;防御側にモブキャラを指定
; CALL CLOSE_COMBAT()                                    ;戦闘イベントを実行
;
;(※より具体的な実装例はQUEST_0,QUEST_1等をを参照)
;-------------------------------------------------
@CLOSE_COMBAT(DIC_OPTIONS = "")
#DIMS DIC_OPTIONS
#DIM  DYNAMIC BATTLE_RESULT

CALL CLOSE_COMBAT_SETUP()
;戦闘イベントでのみ使用するスプライトを準備
CALL CLOSE_COMBAT_SETUP_SPRITE()
;戦闘用にBGMが指定されていたらそれを流す
IF DIC_CONTAINSKEY(DIC_OPTIONS, "BGM")
    CALL FL_PLAYBGM(DIC_GET(DIC_OPTIONS, "BGM"))
ENDIF

;戦闘メイン処理
CALL CLOSE_COMBAT_MAIN(DIC_OPTIONS)
BATTLE_RESULT = RESULT

;戦闘後に空腹度を増加
CALL CLOSE_COMBAT_EXIT_INCREASE_HUNGER_LEVEL(1)

;戦闘イベントで使用したスプライトを破棄
CALL CLOSE_COMBAT_DISPOSE_SPRITE()
;戦闘前に鳴っていたBGMに戻す
IF DIC_CONTAINSKEY(DIC_OPTIONS, "BGM")
    IF !DIC_CONTAINSKEY(DIC_OPTIONS, "BGM_NOT_AUTOSTOP")
        CALL CC_STOPBGM()
    ENDIF
ENDIF
RETURN BATTLE_RESULT

;-------------------------------------------------
; 戦闘開始前の初期処理
;-------------------------------------------------
@CLOSE_COMBAT_SETUP()
#DIM  DYNAMIC IDX1, CC_MAX_MEMBER_NUM
#DIM  DYNAMIC IDX2, CC_MAX_MEMBER_NUM
;同名のキャラクターがいる場合はナンバリング
VARI I
VARI J
VARI MEM_CNT
VARI SAME_NAME_CNT
VARS CHARA_NAME
MEM_CNT = DT_SELECT("CC_ACTOR",,, IDX1)
FOR I, 0, MEM_CNT
    CHARA_NAME '= DT_CELL_GETS("CC_ACTOR", IDX1:I, "CHARA_NAME", 1)
    SAME_NAME_CNT = DT_SELECT("CC_ACTOR", @"CHARA_NAME = '%CHARA_NAME%'",, IDX2)
    IF SAME_NAME_CNT > 1
        FOR J, 0, SAME_NAME_CNT
            DT_CELL_SET "CC_ACTOR", IDX2:J, "CHARA_NAME", @"%CHARA_NAME%%TOFULL(TOSTR(J + 1))%", 1
        NEXT
    ENDIF
NEXT

;-------------------------------------------------
;戦闘処理本体
;-------------------------------------------------
; #region @CLOSE_COMBAT_MAIN
@CLOSE_COMBAT_MAIN(DIC_OPTIONS)
#DIMS DIC_OPTIONS
#DIMS DYNAMIC ACTOR_LIST, CC_MAX_MEMBER_NUM + 1
#DIM  DYNAMIC ACTOR_DID
#DIM  DYNAMIC ACTOR_CHARA_ID
#DIM  DYNAMIC TARGET_DID
#DIM  DYNAMIC SIDE
#DIM  DYNAMIC IS_PLAYABLE
#DIM  ITER_I
#DIM  WINNER
#DIM  AUTO_MODE
#DIM  ACTOR_NPC_ONLY

;初期処理
;-------------------------------------------------
;メッセージウィンドウに出力するメッセージを初期化
CALL CC_CREATE_MESSAGE_TABLE
;全メンバーの行動状態を初期化
CALL CLOSE_COMBAT_INIT_ACTION()
;オートフラグを初期化
CC_AUTO_MODE = 0
;参加キャラがNPCのみか判定
ACTOR_NPC_ONLY = CLOSE_COMBAT_GET_ACTOR_NPC_ONLY()

;戦闘開始メッセージ
;-------------------------------------------------
CALL CC_PRINT("")
CALL CC_PRINT("")
CALL CC_PRINT("")
LOCALS = %TAG_PRINT_SHAPE(@"@C:{カラー_注意}@―― !! BATTLE START !! ――@/C@", 164, 1, 2)%
CALL CC_PRINT(LOCALS)
CALL CLOSE_COMBAT_DRAW_WINDOW()

;敗北イベント予告
IF DIC_CONTAINSKEY(DIC_OPTIONS, "HAS_DEFEAT_EVENT")
    CALL CC_PRINT(@"@C:{カラー_ピンク}@❤ ここでの敗北は悲惨な結果を招くかもしれない……@/C@")
    CALL CLOSE_COMBAT_DRAW_WINDOW()
ENDIF

;戦闘開始時に発動する効果の処理。
CALL CLOSE_COMBAT_OPENING_ACTION

;初期フローを行動前にセット
CC_FLOW '= "BEFORE_ACT"

;メインループ
;-------------------------------------------------
WHILE 1
    CALL CLOSE_COMBAT_JUDGE()
    IF RESULT != 0
        WINNER = RESULT
        ;戦闘決着時にターン終了扱いとする
        CALL CLOSE_COMBAT_TURNEND_CHANGE_STATE()
        BREAK
    ENDIF
    CALL CLOSE_COMBAT_INIT_ACTION()
    CALL CLOSE_COMBAT_SET_ORDER(ACTOR_LIST)
    ACTOR_DID = TOINT(DIC_GET(ACTOR_LIST:0, "ACTOR_DID"))
    ACTOR_CHARA_ID = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "CHARA_ID", 1)
    IS_PLAYABLE = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "IS_PLAYABLE", 1)

    SELECTCASE CC_FLOW
        CASE "BEFORE_ACT"
            CALL CC_TRIGGER_SP_TOKEN_PASSIVE_SKILL("BEFORE_ACT", ACTOR_DID)
            ;操作可能な自陣営キャラの場合は攻撃前に入力指示を挟む
            IF ACTOR_CHARA_ID >= 0 && IS_PLAYABLE
                CC_FLOW '= "INPUT"
                ;操作不可キャラの場合
            ELSEIF ACTOR_CHARA_ID < 0
                ;観戦モードの場合は入力指示を表示
                IF ACTOR_NPC_ONLY
                    CC_FLOW '= "INPUT"
                    ;通常モードの場合は入力指示を省略
                ELSE
                    CC_FLOW '= "ATTACK"
                ENDIF
                ;操作不可な自陣営キャラの場合は入力指示を省略
            ELSE
                CC_FLOW '= "ATTACK"
            ENDIF
        CASE "INPUT"
            WHILE 1
                CALL CC_COMBAT_INPUT_SHOW(ACTOR_DID,ACTOR_NPC_ONLY)
                CALL CLOSE_COMBAT_DRAW_WINDOW(ACTOR_DID)
                SIF RESULT
                    BREAK
            WEND
            CC_FLOW '= "ATTACK"
        CASE "ATTACK"
            IF !IS_PLAYABLE
                ;非プレイヤーキャラの特殊行動
                CALL CLOSE_COMBAT_SET_ENEMY_ACTION(ACTOR_DID)
            ELSEIF CC_AUTO_MODE == 2
                ;スキルオートの場合、スキルを選択
                CALL CLOSE_COMBAT_SET_ALLY_AUTO_ACTION(ACTOR_DID)
            ENDIF
            CALL CLOSE_COMBAT_SET_TARGET(ACTOR_DID)
            TARGET_DID = RESULT
            CALL CLOSE_COMBAT_BEFORE_ATTACK(ACTOR_DID, TARGET_DID)
            CALL CLOSE_COMBAT_ATTACK(ACTOR_DID, TARGET_DID)
            CALL CLOSE_COMBAT_AFTER_ATTACK(ACTOR_DID, TARGET_DID)
            ;攻撃終了後の処理
            CALL CLOSE_COMBAT_RELEASE_ACTION()
            CC_FLOW '= "BEFORE_ACT"
        CASE "NEXT_ROUND"
            CALL CC_PRINT("")
            CALL CC_PRINT("")
            CALL CC_PRINT("")
            LOCALS = %TAG_PRINT_SHAPE(@"@C:{カラー_注意}@―― ROUND {CC_ROUND_COUNT} ――@/C@", 164, 1, 2)%
            CALL CC_PRINT(LOCALS)
            CC_FLOW '= "BEFORE_ACT"
    ENDSELECT

    CALL CLOSE_COMBAT_DRAW_WINDOW(ACTOR_DID)
WEND

;戦闘終了
;-------------------------------------------------
CC_FLOW = "RESULT"
IF WINNER == 1
    LOCALS = %TAG_PRINT_SHAPE(@"@C:{カラー_注意}@―― Attacker victory! ――@/C@", 164, 1, 2)%
ELSE
    LOCALS = %TAG_PRINT_SHAPE(@"@C:{カラー_注意}@―― Defender victory! ――@/C@", 164, 1, 2)%
ENDIF
CALL CC_PRINT("")
CALL CC_PRINT("")
CALL CC_PRINT("")
CALL CC_PRINT(LOCALS)
CALL CLOSE_COMBAT_DRAW_WINDOW()
FORCEWAIT

;戦闘用ウィンドウを破棄
CALL WndMgr_DestroyWindow(-1)

;アクション記録を破棄
CALL CC_RELEASE_ALL_ACT_FLAG
CALL CC_RELEASE_ALL_TRIGGERED_SKILL_FLAG
DT_CLEAR "CC_ACTION"
;アクターフラグを破棄
CALL CC_RELEASE_ALL_ACTOR_FLAG

RETURN WINNER
; #endregion

;-------------------------------------------------
;参加メンバーの状態遷移
;MEM_LIST ATTACKER 側のリスト
;MEM_LIST DEFENDER 側のリスト
;-------------------------------------------------
; #region @CLOSE_COMBAT_INIT_ACTION
@CLOSE_COMBAT_INIT_ACTION()
#DIM DYNAMIC MEM_CNT
#DIM DYNAMIC SIDE
#DIM DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIM DYNAMIC 戦闘可能メンバカウンタ
#DIM DYNAMIC 行動済メンバカウンタ

;攻撃側→防御側の順で判定
CALL CLOSE_COMBAT_INIT_ACTION_CHANGE_STATE(0)
行動済メンバカウンタ += RESULT
CALL CLOSE_COMBAT_INIT_ACTION_CHANGE_STATE(1)
行動済メンバカウンタ += RESULT

;戦闘可能メンバーの総数をカウントする
;攻撃側→防御側の順で判定
戦闘可能メンバカウンタ = 0
FOR SIDE, 0, 2
    MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {SIDE}",,IDX)
    FOR LOCAL, 0, MEM_CNT
        IF DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "STATE", 1) != "戦闘不能"
            戦闘可能メンバカウンタ ++
        ENDIF
    NEXT
NEXT

;戦闘が行える状態の全メンバー行動済みの場合はターン終了処理
IF 行動済メンバカウンタ == 戦闘可能メンバカウンタ
    CALL CLOSE_COMBAT_TURNEND()
ENDIF
RETURN
; #endregion

@CLOSE_COMBAT_INIT_ACTION_CHANGE_STATE(SIDE)
#DIM  SIDE
#DIM  DYNAMIC MEM_CNT
#DIM  DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIMS DYNAMIC STATE
#DIM  DYNAMIC 行動済メンバカウンタ

MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {SIDE}",, IDX)
FOR LOCAL, 0, MEM_CNT
    STATE = %DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "STATE", 1)%
    IF STATE == "行動済"
        行動済メンバカウンタ ++
    ELSEIF STATE == "攻撃" || STATE == "行動不能"
        ;再行動判定
        IF CC_SP_TOKEN_NUM(IDX:LOCAL, "REACT") > 0
            CALL CC_SUB_SP_TOKEN(IDX:LOCAL, "REACT", 1)
            DT_CELL_SET "CC_ACTOR", IDX:LOCAL, "STATE", "待機", 1
        ELSE
            DT_CELL_SET "CC_ACTOR", IDX:LOCAL, "STATE", "行動済", 1
            行動済メンバカウンタ ++
        ENDIF
    ELSEIF STATE != "戦闘不能"
        DT_CELL_SET "CC_ACTOR", IDX:LOCAL, "STATE", "待機", 1
    ENDIF
NEXT

RETURN 行動済メンバカウンタ

;-------------------------------------------------
; ラウンド経過時処理
;全メンバー行動済みの場合ラウンド経過処理を行い、ラウンド数を加算
;-------------------------------------------------
@CLOSE_COMBAT_TURNEND()

CALL CLOSE_COMBAT_TURNEND_CHANGE_STATE()
CC_ROUND_COUNT ++
CC_FLOW '= "NEXT_ROUND"
CALL CC_PASSIVE_CHECK_ALL("TURN_END")
CALL CC_SP_TOKEN_TRIGGER_CHECK("TURN_END")
CALL CLOSE_COMBAT_DRAW_WINDOW()
RETURN

;-------------------------------------------------
; 全メンバー行動済みの場合は戦闘不能メンバー以外を全員待機に
; メンバーのスキルクールタイムを減少
;-------------------------------------------------
@CLOSE_COMBAT_TURNEND_CHANGE_STATE()
#DIM  SIDE
#DIM  DYNAMIC MEM_CNT
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC FACTION
#DIM  DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIM  DYNAMIC SKILL_SLOT_DID, MAX_SKILL_SLOT
#DIM  DYNAMIC SKILL_SLOT_IDX
#DIM  DYNAMIC SKILL_COOLTIME
#DIMS DYNAMIC STATE
#DIM  ITER_I
#DIM  ITER_J

MEM_CNT = DT_SELECT("CC_ACTOR",,, IDX)
FOR ITER_I, 0, MEM_CNT
    STATE = %DT_CELL_GETS("CC_ACTOR", IDX:ITER_I, "STATE", 1)%
    SIF STATE == "戦闘不能"
        CONTINUE
    ;スキルクールタイムを減少
    CHARA_ID = DT_CELL_GET("CC_ACTOR", IDX:ITER_I, "CHARA_ID", 1)
    DT_SELECT "CC_SKILL_SLOT",@"CHARA_ID = {CHARA_ID}",, SKILL_SLOT_DID
    FOR ITER_J, 0, RESULT
        SKILL_COOLTIME = DT_CELL_GET("CC_SKILL_SLOT", SKILL_SLOT_DID:ITER_J, "COOLTIME", 1)
        IF SKILL_COOLTIME > 0
            DT_CELL_SET "CC_SKILL_SLOT", SKILL_SLOT_DID:ITER_J, "COOLTIME", SKILL_COOLTIME - 1, 1
            SKILL_SLOT_IDX = DT_CELL_GET("CC_SKILL_SLOT", SKILL_SLOT_DID:ITER_J, "SKILL_SLOT_IDX", 1)
            IF SKILL_SLOT_IDX < 3
                ACTIVE_SKILL_COOLTIME:CHARA_ID:SKILL_SLOT_IDX = SKILL_COOLTIME - 1
            ENDIF
        ENDIF
    NEXT
    ; IF CHARA_ID != -1
    ;     FOR ITER_J, 0, VARSIZE("ACTIVE_SKILL_COOLTIME")
    ;         SIF ACTIVE_SKILL_COOLTIME:CHARA_ID:ITER_J > 0
    ;             ACTIVE_SKILL_COOLTIME:CHARA_ID:ITER_J --
    ;         SIF WPN_ACTIVE_SKILL_COOLTIME:CHARA_ID:ITER_J > 0
    ;             WPN_ACTIVE_SKILL_COOLTIME:CHARA_ID:ITER_J --
    ;     NEXT
    ; ENDIF
    ;ステートを待機に変更
    DT_CELL_SET "CC_ACTOR", IDX:ITER_I, "STATE", "待機", 1
    ;生存している味方に好感度追加
    IF CHARA_ID >= 0
        FACTION = DT_CELL_GET("CC_ACTOR", IDX:ITER_I, "FACTION", 1)
        IF FACTION == 所属_プレイヤー
            CFLAG:CHARA_ID:QST好感度ボーナス ++
        ENDIF
    ENDIF
NEXT
;DT_TOXML "CC_ACTOR"

;-------------------------------------------------
;行動順リストの作成
;戦闘値の高い順に行動させる
;MEM_LIST   ATTACKER 側のリスト
;MEM_LIST   DEFENDER 側のリスト
;ACTOR_LIST 行動順の作成
;-------------------------------------------------
@CLOSE_COMBAT_SET_ORDER(ACTOR_LIST)
#DIMS REF ACTOR_LIST
#DIM  DYNAMIC ACTOR_LIST_IDX
#DIM  DYNAMIC MEM_CNT
#DIM  DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIMS STATE

#DIM DYNAMIC AGILITY

VARSET ACTOR_LIST

MEM_CNT = DT_SELECT("CC_ACTOR",,, IDX)
FOR LOCAL, 0, MEM_CNT
    STATE = %DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "STATE", 1) %
    SIF STATE == "戦闘不能" || STATE == "行動済"
        CONTINUE
    ACTOR_LIST:ACTOR_LIST_IDX = %DIC_SET(ACTOR_LIST:ACTOR_LIST_IDX, "ACTOR_DID", TOSTR(DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "ID", 1)))%
    ;行動力の補正などが必要であればここで実施
    ;今はないので単純に代入
    AGILITY =  DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "AGILITY", 1)
    ;トークンによる行動力の補正
    ;捕罠
    SIF CC_SP_TOKEN_NUM(IDX:LOCAL, "TRAPPED") > 0
        AGILITY = 1
    ACTOR_LIST:ACTOR_LIST_IDX = %DIC_SET(ACTOR_LIST:ACTOR_LIST_IDX, "行動力", TOSTR(AGILITY))%
    ACTOR_LIST_IDX ++
NEXT
ACTOR_LIST:(ACTOR_LIST_IDX) '= "-1"

;ACTOR_LISTの内容を""内の順に並べ替える
CALL ARRAYSORT_DIC(ACTOR_LIST, "行動力", 1)

RETURN

;-------------------------------------------------
;勝利判定
;-------------------------------------------------
@CLOSE_COMBAT_JUDGE()
#DIM DYNAMIC MEMBER_NUM
#DIM DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIM DYNAMIC 戦闘不能カウンタ
#DIM SIDE

SIF CC_FORCE_END
    RETURN CC_FORCE_END

;攻撃側→防御側の順で判定
FOR SIDE, 0, 2
    戦闘不能カウンタ = 0
    MEMBER_NUM = DT_SELECT("CC_ACTOR", @"SIDE = {SIDE}",,IDX)
    FOR LOCAL, 0, MEMBER_NUM
        IF DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "STATE", 1) == "戦闘不能"
            戦闘不能カウンタ ++
        ENDIF
    NEXT
    IF 戦闘不能カウンタ == MEMBER_NUM
        RETURN SIDE + 1
    ENDIF
NEXT

RETURN 0
;-------------------------------------------------
;テキストメッセージ出力
;-------------------------------------------------
@CC_PRINT(TEXT, ACTION_DID = -1)
#DIMS TEXT
#DIM ACTION_DID
{
    DT_ROW_ADD "CC_MESSAGE_TABLE"
        ,"MESSAGE", TEXT
        ,"ACTION_DID", ACTION_DID
}
RETURN RESULT

;-------------------------------------------------
;同じ行のテキストメッセージ出力
;-------------------------------------------------
@CC_PRINT_SAME_LINE(TEXT, MESSAGE_DID)
#DIMS DYNAMIC TEXT
#DIM MESSAGE_DID
#DIMS NEW_TEXT

NEW_TEXT = %DT_CELL_GETS("CC_MESSAGE_TABLE", MESSAGE_DID, "MESSAGE", 1)%%TEXT%

DT_CELL_SET "CC_MESSAGE_TABLE", MESSAGE_DID, "MESSAGE", NEW_TEXT, 1

;-------------------------------------------------
;引数分の文字列から条件を満たすもののみランダムに一つ出力
;-------------------------------------------------
@CC_PRINT_RANDC(ARGS:0 = "" ,ARG:0 = 1 ,ARGS:1 = "", ARG:1 = 1 ,ARGS:2 = "", ARG:2 = 1 ,ARGS:3 = "", ARG:3 = 1 ,ARGS:4 = "", ARG:4 = 1 ,ARGS:5 = "", ARG:5 = 1 ,ARGS:6 = "", ARG:6 = 1 ,ARGS:7 = "", ARG:7 = 1 , ARGS:8 = "", ARG:8 = 1 ,ARGS:9 = "", ARG:9 = 1,ARGS:14 = "" ,ARG:14 = 1 ,ARGS:15 = "", ARG:15 = 1 ,ARGS:16 = "", ARG:16 = 1 ,ARGS:17 = "", ARG:17 = 1 ,ARGS:18 = "", ARG:18 = 1,ARGS:19 = "", ARG:19 = 1)
#DIMS DYNAMIC LIST_TEXT
FOR LOCAL, 0, 20
    SIF !ARG:LOCAL
        CONTINUE
    IF ARGS:LOCAL != ""
        LIST_TEXT = %LIST_ADD(LIST_TEXT, ARGS:LOCAL)%
    ENDIF
NEXT
SIF LIST_COUNT(LIST_TEXT) == 0
    RETURN

CALL CC_PRINT(@"@C:{カラー_ピンク}@%LIST_RAND(LIST_TEXT)%@/C@")
RETURN RESULT
;-------------------------------------------------
;同じ行の引数分の文字列から条件を満たすもののみランダムに一つ出力
;-------------------------------------------------
@CC_PRINT_SAME_LINE_RANDC(MESSAGE_DID, ARGS:0 = "" ,ARG:0 = 1 ,ARGS:1 = "", ARG:1 = 1 ,ARGS:2 = "", ARG:2 = 1 ,ARGS:3 = "", ARG:3 = 1 ,ARGS:4 = "", ARG:4 = 1 ,ARGS:5 = "", ARG:5 = 1 ,ARGS:6 = "", ARG:6 = 1 ,ARGS:7 = "", ARG:7 = 1 , ARGS:8 = "", ARG:8 = 1 ,ARGS:9 = "", ARG:9 = 1,ARGS:14 = "" ,ARG:14 = 1 ,ARGS:15 = "", ARG:15 = 1 ,ARGS:16 = "", ARG:16 = 1 ,ARGS:17 = "", ARG:17 = 1 ,ARGS:18 = "", ARG:18 = 1,ARGS:19 = "", ARG:19 = 1)
#DIMS DYNAMIC LIST_TEXT
#DIM MESSAGE_DID
FOR LOCAL, 0, 20
    SIF !ARG:LOCAL
        CONTINUE
    IF ARGS:LOCAL != ""
        LIST_TEXT = %LIST_ADD(LIST_TEXT, ARGS:LOCAL)%
    ENDIF
NEXT
SIF LIST_COUNT(LIST_TEXT) == 0
    RETURN

CALL CC_PRINT_SAME_LINE(@"@C:{カラー_ピンク}@%LIST_RAND(LIST_TEXT)%@/C@", MESSAGE_DID)

;-------------------------------------------------
;画面描画と入力処理
; RETURN 0:再入力 1:入力完了
;-------------------------------------------------
@CLOSE_COMBAT_DRAW_WINDOW(ACTOR_DID = 0, OPTIONS = "")
#DIM  ACTOR_DID
#DIMS OPTIONS
#DIM DYNAMIC WND_ID_MEM, CC_MAX_MEMBER_NUM
#DIMS DYNAMIC BTN_ID

;#DIM CONST TOTAL_WND_WIDTH = 144
#DIM CONST TOTAL_WND_WIDTH = 166
#DIM CONST LIST_WND_WIDTH = 80
#DIM CONST LIST_WND_HEIGHT = 44
#DIM CONST BOTTOM_WND_HEIGHT = 10
#DIM CONST MARGIN = 0
#DIM DYNAMIC LINE_NUM
#DIM DYNAMIC IDX
#DIM DYNAMIC LINE_COUNT

SIF DT_ROW_LENGTH("CC_MESSAGE_TABLE") == 0
    RETURN 0

REDRAW 0
;画面消去
CLEARLINE LINECOUNT
;ウィンドウ初期化
CALL WndMgr_DestroyWindow(-1)
;ウィンドウ生成
; CALL WndMgr_CreateWindow(WND_ID_LEFT, 2, 2, LIST_WND_WIDTH + 2, LIST_WND_HEIGHT, 2)
; CALL WndMgr_CreateWindow(WND_ID_RIGHT, LIST_WND_WIDTH + 6, 2, LIST_WND_WIDTH + 2, LIST_WND_HEIGHT, 2)
CALL WndMgr_CreateWindow(WND_ID_BOTTOM, 2, 2, TOTAL_WND_WIDTH, BOTTOM_WND_HEIGHT, 2)

;攻撃側、防御側メンバーリストの描画
CALL CLOSE_COMBAT_DRAW_MEMBER_WINDOW(1, ACTOR_DID)
CALL CLOSE_COMBAT_DRAW_MEMBER_WINDOW(0, ACTOR_DID)
FOR LOCAL, 0, LIST_WND_HEIGHT
    PRINTL
NEXT

;効果音を鳴らす
IF CC_SE != ""
    CALL FL_PLAYSE(CC_SE)
    CC_SE '= ""
ENDIF

;メッセージウィンドウの描画
LINE_NUM = DT_ROW_LENGTH("CC_MESSAGE_TABLE")
;CC_MESSAGE_TABLEの連番
IDX = 0
;行番号(ページ送り時に0に戻す)
LINE_COUNT = 0
WHILE IDX < LINE_NUM
    CALL WndMgr_TextSet(WND_ID_BOTTOM, LINE_COUNT, DT_CELL_GETS("CC_MESSAGE_TABLE", IDX, "MESSAGE"))
    IDX++
    LINE_COUNT ++
    ;規定行でページ送り
    IF  IDX > 0 && IDX % (BOTTOM_WND_HEIGHT - 3) == 0 && IDX < LINE_NUM
        LOCALS = %TAG_PRINT_SHAPE(@"▼", TOTAL_WND_WIDTH - 2, 1, 2)%
        CALL WndMgr_TextSet(WND_ID_BOTTOM, LINE_COUNT, LOCALS)
        CALL WndMgr_DisplayAll()
        CALL CLOSE_COMBAT_DRAW_WINDOW_SHOW_PORTRAIT(ACTOR_DID)
        IF CC_AUTO_MODE == 0
            WAIT
        ELSE
            TWAIT 75, 0
        ENDIF
        CALL WndMgr_TextClear(WND_ID_BOTTOM)
        LINE_COUNT = 0
        CLEARLINE BOTTOM_WND_HEIGHT + 3
    ENDIF
WEND
CALL WndMgr_DisplayAll()
;メッセージ用テーブルを初期化
DT_CLEAR "CC_MESSAGE_TABLE"

CALL CLOSE_COMBAT_DRAW_WINDOW_SHOW_PORTRAIT(ACTOR_DID)

IF DIC_CONTAINSKEY(OPTIONS, "TARGET_SELECT")
    CALL CLOSE_COMBAT_DRAW_TARGET_SELECT_BTN_OVERLAY(TOINT(DIC_GET(OPTIONS, "TARGET_SELECT")))
ENDIF

IF CC_AUTO_MODE == 0
    CALL CLOSE_COMBAT_INPUT(OPTIONS)
ELSE
    CALL CLOSE_COMBAT_INPUT_AUTO()
ENDIF

;入力完了結果を返却
RETURN RESULT

;-------------------------------------------------
;メッセージテーブルを作成
;-------------------------------------------------
@CC_CREATE_MESSAGE_TABLE
#DIMS CONST DB_NAME = "CC_MESSAGE_TABLE"

IF DT_EXIST(DB_NAME)
    DT_CLEAR DB_NAME
    RETURN
ENDIF

DT_CREATE DB_NAME
DT_COLUMN_ADD DB_NAME, "MESSAGE" ,"string"
DT_COLUMN_ADD DB_NAME, "ACTION_DID" ,"int64"
;DT_COLUMN_ADD DB_NAME, "SE" ,"string"

;-------------------------------------------------
;ポートレイトを表示
;-------------------------------------------------
@CLOSE_COMBAT_DRAW_WINDOW_SHOW_PORTRAIT(ACTOR_DID)
#DIM ACTOR_DID
#DIMS CONST PORTRAIT_CONFIG = "[サイズ:250px][POS_X:6400][POS_Y:-1625][DEPTH:-1][BORDER:0]"

VARI CHARA_ID
VARI SHOW_PORTRAIT
VARS DIC_PORTRAIT
VARS DIC_PORTRAIT_OPTIONS

CHARA_ID = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "CHARA_ID", 1)
SHOW_PORTRAIT = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "SHOW_PORTRAIT", 1)
DIC_PORTRAIT_OPTIONS = %DT_CELL_GETS("CC_ACTOR", ACTOR_DID, "PORTRAIT_OPTIONS", 1)%

IF CHARA_ID != -1
    IF CSTR:CHARA_ID:キャラ顔グラ == "FACE_DUMMY" && CFLAG:CHARA_ID:ポートレイト画像タイプ == 0
        SHOW_PORTRAIT = 0
    ELSE
        IF DIC_CONTAINSKEY(DIC_PORTRAIT_OPTIONS, "SHOW_PORTRAIT")
            SHOW_PORTRAIT = DIC_GETINT(DIC_PORTRAIT_OPTIONS, "SHOW_PORTRAIT")
        ELSE
            SHOW_PORTRAIT = 1
        ENDIF
    ENDIF
ELSE
    SHOW_PORTRAIT = 0
ENDIF

IF SHOW_PORTRAIT
    SELECTCASE CC_FLOW
        CASE "ATTACK"
            IF DT_CELL_GETS("CC_ACTOR", ACTOR_DID, "PORTRAIT_EFFECT", 1) == "ORGASM"
                {
                    CALL DRAW_PORTRAIT(CHARA_ID
                        ,@"[目:%S_R("閉じ(張_涙)")%]"
                        +@"[眉:%S_R("怒り/困り")%]"
                        +@"[口:%S_R("むす/叫び/叫び")%]"
                        +@"[OVL_表情:%S_R("赤面")%]"
                        +@"[OVL_表情2:%S_R("吐息")%]"
                        +@"[OVL_漫符:%S_R("絶頂")%]"
                        +@"[OVL_漫符2:%S_R("/ハート")%]"
                        +@"%PORTRAIT_CONFIG%"
                        )
                }
            ELSE
                IF DIC_PORTRAIT_OPTIONS == ""
                    DIC_PORTRAIT '= @"[目:%S_R("通常/細目")%][眉:%S_R("怒り")%][口:%S_R("むす/むす/叫び")%]"
                ELSE
                    DIC_PORTRAIT '= @"%DIC_PORTRAIT_OPTIONS%"
                ENDIF
                CALL DRAW_PORTRAIT(CHARA_ID, @"%DIC_PORTRAIT%%PORTRAIT_CONFIG%")
            ENDIF
            IF RESULT == 0
                PRINTL
            ENDIF
        CASEELSE
            PRINTL
    ENDSELECT
ELSE
    PRINTL
ENDIF
DT_CELL_SET "CC_ACTOR", ACTOR_DID, "PORTRAIT_EFFECT", "", 1
RETURN

;-------------------------------------------------
; アクティブスキルSLOTの描画
;-------------------------------------------------
@CLOSE_COMBAT_DRAW_SKILL_BUTTON(WND_ID_MEM, CHARA_DID)
#DIM  WND_ID_MEM
#DIM  CHARA_DID
;キャラ
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC F_COL
#DIMS DYNAMIC BTN_ID
#DIMS DYNAMIC SKILL_NAME
#DIMS DYNAMIC STATE
;装備
#DIM  DYNAMIC EQUIP_DID
#DIM  DYNAMIC EQUIPNUM
#DIMS DYNAMIC _DIC_WPN_SKILL
#DIM  DYNAMIC SKILL_DID, VARSIZE("SKILL_DEF_LIST")
;スキル使用可否判定
#DIMS DYNAMIC SKILL_DEF_NAME
#DIM  DYNAMIC SKILL_SLOT_IDX
#DIM  DYNAMIC IS_CASTABLE
#DIM  DYNAMIC SKILL_COOLTIME
#DIMS DYNAMIC DIC_REQITEM_TOCAST
#DIMS DYNAMIC DIC_REQTOKEN_TOCAST
#DIMS DYNAMIC REQ_ITEM_NAME
#DIMS DYNAMIC COST
#DIM  DYNAMIC REQ_ITEM_NUM
#DIM  DYNAMIC ITER_J
#DIMS DYNAMIC CHARA_SKILL_STR
#DIMS DYNAMIC EQUIP_SKILL_STR1
#DIMS DYNAMIC EQUIP_SKILL_STR2

;ACTOR_DIDからキャラクター情報取得
CHARA_ID = DT_CELL_GET("CC_ACTOR", CHARA_DID, "CHARA_ID", 1)
STATE = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "STATE", 1)%

;;キャラクタースキルの描画
SIF CHARA_ID == -1
    RETURN
FOR LOCAL, 0, LIST_COUNT(_LIST_ACTIVE_SKILL_SLOT:CHARA_ID:0)
    F_COL = カラー_白
    SIF DT_CELL_GET("CC_ACTOR", CHARA_DID, "SELECTED_SKILL_SLOT", 1) == LOCAL
        F_COL = カラー_選択中
    SKILL_DEF_NAME = %LIST_GET(_LIST_ACTIVE_SKILL_SLOT:CHARA_ID:0, LOCAL)%
    SKILL_SLOT_IDX = LOCAL
    BTN_ID '= @"\\[INPUT_FROM:SKILL_SLOT\\]\\[CHARA_DID:{CHARA_DID}\\]\\[SKILL_SLOT_IDX:{LOCAL}\\]"
    SKILL_NAME = %GET_SKILL_NAME(SKILL_DEF_NAME, スキル_ジャンル_戦闘)%
    IF STRLENS(SKILL_NAME) > 12
        SKILL_NAME = %TAG_PRINT_SHAPE(TOHALF(SKILL_NAME), 12, 0)%
    ENDIF
    ;実行可否判定
    CALL CLOSE_COMBAT_SKILL_CAN_CAST(CHARA_DID, SKILL_DEF_NAME, SKILL_SLOT_IDX)
    IS_CASTABLE = RESULT
    IF IS_CASTABLE == 0
        SKILL_COOLTIME = RESULT:1
        F_COL = カラー_選択不可
        SKILL_NAME += @"@C:{カラー_注釈}@({SKILL_COOLTIME})@/C@"
        LOCALS = %TAG_PRINT_SHAPE(@"@C:{F_COL}@[{LOCAL + 1}]%SKILL_NAME%@/C@", 20, 1)%
    ELSEIF IS_CASTABLE == -1 || STATE == "攻撃"
        F_COL = カラー_選択不可
        LOCALS = %TAG_PRINT_SHAPE(@"@C:{F_COL}@[{LOCAL + 1}]%SKILL_NAME%@/C@", 20, 1)%
    ELSE
        LOCALS = %TAG_PRINT_SHAPE(@"@C:{F_COL}@@B:%BTN_ID%@[{LOCAL + 1}] %SKILL_NAME%@/B@@/C@", 20, 1)%
    ENDIF
    CHARA_SKILL_STR += CONV_TAG2H(LOCALS)
NEXT

;;装備スキルの描画
LOCALS '= ""
;DT_TOXML "CC_SKILL_SLOT"
DT_SELECT "CC_SKILL_SLOT",@"CHARA_ID = {CHARA_ID} AND NOT EQUIP_DID = 0","SKILL_SLOT_IDX ASC",SKILL_DID
FOR LOCAL, 0, RESULT
    F_COL = カラー_白
    SIF DT_CELL_GET("CC_ACTOR", CHARA_DID, "SELECTED_SKILL_SLOT", 1) == LOCAL + 3
        F_COL = カラー_選択中
    SKILL_DEF_NAME = %DT_CELL_GETS("CC_SKILL_SLOT", SKILL_DID:LOCAL, "SKILL_DEF_NAME", 1)%
    EQUIP_DID = DT_CELL_GET("CC_SKILL_SLOT", SKILL_DID:LOCAL, "EQUIP_DID", 1)
    SKILL_SLOT_IDX = DT_CELL_GET("CC_SKILL_SLOT", SKILL_DID:LOCAL, "SKILL_SLOT_IDX", 1)
    BTN_ID '= @"\\[INPUT_FROM:SKILL_SLOT\\]\\[CHARA_DID:{CHARA_DID}\\]\\[SKILL_SLOT_IDX:{LOCAL + 3}\\]"
    SKILL_NAME = %GET_WPN_SKILL_NAME(SKILL_DEF_NAME, スキル_ジャンル_戦闘)%
    IF STRLENS(SKILL_NAME) > 12
        SKILL_NAME = %TAG_PRINT_SHAPE(TOHALF(SKILL_NAME), 12, 0)%
    ENDIF
    ;実行可否判定
    CALL CLOSE_COMBAT_SKILL_CAN_CAST(CHARA_DID, SKILL_DEF_NAME, SKILL_SLOT_IDX)
    IS_CASTABLE = RESULT
    IF IS_CASTABLE == 0
        SKILL_COOLTIME = RESULT:1
        F_COL = カラー_選択不可
        SKILL_NAME += @"@C:{カラー_注釈}@({SKILL_COOLTIME})@/C@"
        LOCALS = %TAG_PRINT_SHAPE(@"@C:{F_COL}@[{LOCAL + 4}]%SKILL_NAME%@/C@", 20, 1)%
    ELSEIF IS_CASTABLE == -1 || STATE == "攻撃"
        F_COL = カラー_選択不可
        LOCALS = %TAG_PRINT_SHAPE(@"@C:{F_COL}@[{LOCAL + 4}]%SKILL_NAME%@/C@", 20, 1)%
    ELSE
        LOCALS = %TAG_PRINT_SHAPE(@"@C:{F_COL}@@B:%BTN_ID%@[{LOCAL + 4}] %SKILL_NAME%@/B@@/C@", 20, 1)%
    ENDIF
    IF LOCAL < 3
        EQUIP_SKILL_STR1 += CONV_TAG2H(LOCALS)
    ELSE
        EQUIP_SKILL_STR2 += CONV_TAG2H(LOCALS)
    ENDIF
NEXT
RESULTS:0 = %CHARA_SKILL_STR%
RESULTS:1 = %EQUIP_SKILL_STR1%
RESULTS:2 = %EQUIP_SKILL_STR2%

RETURN

;-------------------------------------------------
;入力受付処理
; RETURN: 0=再入力, 1=入力完了
;-------------------------------------------------
@CLOSE_COMBAT_INPUT(OPTIONS)
#DIMS OPTIONS
#DIMS DYNAMIC INPUT_VALUES
#DIM  DYNAMIC CHARA_DID
#DIM DYNAMIC SKILL_SLOT_IDX
#DIM DYNAMIC NOW_SELECTED_SLOT_IDX

WHILE 1
    VARSET RESULTS
    INPUTS , 1
    REDRAW 0
    ;CLEARLINE 1
    INPUT_VALUES = %RESULTS:1%
    IF !DIC_CONTAINSKEY(OPTIONS, "TARGET_SELECT")
        ;スキルをクリック
        IF DIC_GET(INPUT_VALUES, "INPUT_FROM") == "SKILL_SLOT"
            CHARA_DID = TOINT(DIC_GET(INPUT_VALUES, "CHARA_DID"))
            SKILL_SLOT_IDX = TOINT(DIC_GET(INPUT_VALUES, "SKILL_SLOT_IDX"))
            NOW_SELECTED_SLOT_IDX = DT_CELL_GET("CC_ACTOR", CHARA_DID, "SELECTED_SKILL_SLOT", 1)
            IF SKILL_SLOT_IDX != NOW_SELECTED_SLOT_IDX
                DT_CELL_SET "CC_ACTOR", CHARA_DID, "SELECTED_SKILL_SLOT", SKILL_SLOT_IDX, 1
                CALL FL_PLAYSE("Switch_0.mp3")
            ELSE
                DT_CELL_SET "CC_ACTOR", CHARA_DID, "SELECTED_SKILL_SLOT", -1, 1
                CALL FL_PLAYSE("Switch_1.mp3")
            ENDIF
            RETURN 0
            ;左クリック
        ELSEIF RESULT:1 == 1
            ;何もない場所をクリック
            IF INPUT_VALUES == "" || INPUT_VALUES == "_"
                BREAK
                ;オートを選択
            ELSEIF DIC_CONTAINSKEY(INPUT_VALUES, "AUTO")
                CC_AUTO_MODE = CC_AUTO_MODE_INPUT + 1
                BREAK
                ;オートの種類を選択するオプションを表示
            ELSEIF DIC_GET(INPUT_VALUES, "AUTO_OPTION") == "1"
                CALL OPTION_POPUP("通常攻撃,スキル,")
                SIF RESULT != -1
                    CC_AUTO_MODE_INPUT = RESULT
                RETURN 0
                ;オートの速度を選択するオプションを表示
            ELSEIF DIC_GET(INPUT_VALUES, "AUTO_OPTION") == "2"
                ;CALL OPTION_POPUP("通常,1.5倍速,2倍速,")
                CALL OPTION_POPUP("Normal,1.5x,2x,4x,8x,MAX")
                IF RESULT == 0
                    CC_AUTO_INPUT_WAIT = 200
                ELSEIF RESULT == 1
                    CC_AUTO_INPUT_WAIT = 133
                ELSEIF RESULT == 2
                    CC_AUTO_INPUT_WAIT = 100
                ENDIF
                RETURN 0
            ENDIF
            IF DIC_CONTAINSKEY(INPUT_VALUES, "FORCE_END")
                CC_FORCE_END = TOINT(DIC_GET(INPUT_VALUES, "FORCE_END"))
                BREAK
            ENDIF
            ;防御を選択
            IF DIC_CONTAINSKEY(INPUT_VALUES, "DEFENCE")
                CHARA_DID = TOINT(DIC_GET(INPUT_VALUES, "CHARA_DID"))
                DT_CELL_SET "CC_ACTOR", CHARA_DID, "SELECTED_SKILL_SLOT", -1, 1
                DT_CELL_SET "CC_ACTOR", CHARA_DID, "SUBSTATE", "防御", 1
                BREAK
            ENDIF
        ELSEIF RESULT:1 == 3;中ボタンクリック
            ;オートを選択したとみなす
            CC_AUTO_MODE = CC_AUTO_MODE_INPUT + 1
            BREAK
        ELSE
            ;ENTER入力を非ボタンクリックとみなす
            BREAK
        ENDIF
    ENDIF
    ;;ターゲット選択処理
    ;左右クリックどちらでも可
    IF RESULT:1
        IF DIC_CONTAINSKEY(INPUT_VALUES, "TARGET_ACTOR_DID")
            CC_MULTI_TARGET_LIST = %DIC_GET(INPUT_VALUES, "TARGET_ACTOR_DID")%
            BREAK
        ENDIF
    ENDIF
    IF INPUT_VALUES != ""
        CLEARLINE 1
    ENDIF
WEND
RETURN 1

;-------------------------------------------------
;入力情報表示
; ACTOR_DID: プレイヤーキャラ
; ACTOR_NPC_ONLY: 0=通常, 1=観戦モード
;-------------------------------------------------
@CC_COMBAT_INPUT_SHOW(ACTOR_DID, ACTOR_NPC_ONLY = 0)
#DIM DYNAMIC ACTOR_DID
#DIM DYNAMIC ACTOR_NPC_ONLY
#DIM DYNAMIC ACTOR_CHARA_ID
#DIM DYNAMIC SIDE

;観戦モード用
IF ACTOR_NPC_ONLY
    IF CC_AUTO_MODE == 0
        CALL CC_PRINT("")
        CALL CC_PRINT(@"@C:{カラー_注釈}@ - [Left click]: Attack - [Right click]: Skill select - [Middle click]: Auto combat@/C@")
        CALL CC_PRINT(@"@C:{カラー_白}@@B:[AUTO:1]@[AUTO]@/B@ : @B:[AUTO_OPTION:2]@[+]Speed - %COMBAT_SPEED_NAME()%@/B@@/C@")
    ELSE
        CALL CC_PRINT(@"@C:{カラー_注釈}@ - *Left click to auto cancel*@/C@")
    ENDIF
    RETURN 0
ENDIF

ACTOR_CHARA_ID = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "CHARA_ID", 1)
;操作不可能キャラの場合
SIF ACTOR_CHARA_ID < 0
    RETURN -1

CALL CC_PRINT(@"◆ %ANAME(ACTOR_CHARA_ID)%'s turn action ◆")
IF CC_AUTO_MODE == 0 && ACTOR_NPC_ONLY == 0
    VARS TOOLTIP
    CALL CC_PRINT(@"@C:{カラー_注釈}@ -左クリック：行動実行 -中クリック：オート戦闘@/C@")
    CALL CC_PRINT(@"@C:{カラー_注釈}@ -アクティブスキルがセットされている場合、対象スキルを右クリックすることでアクティブにできる@/C@")
    TOOLTIP '= "軽減値の50%相当の[バリア]を自身に生成し行動を終了します"
    CALL CC_PRINT(@"@C:{カラー_白}@@B:[DEFENCE:1][CHARA_DID:{ACTOR_DID}]$%TOOLTIP%@[防御]@/B@@/C@")
    CALL CC_PRINT(@"@C:{カラー_白}@@B:[AUTO:1]@[オート]@/B@ : @B:[AUTO_OPTION:1]@[+]優先行動 - %COMBAT_MODE_NAME()%@/B@ @B:[AUTO_OPTION:2]@[+]表示速度 - %COMBAT_SPEED_NAME()%@/B@@/C@")
    CALL CC_PRINT("")
    IF HAS_SKILL(ACTOR_CHARA_ID, "SURRENDER", スキル_大分類_性技)
        SIDE = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "SIDE", 1)
        CALL CC_PRINT(@"@C:{カラー_白}@@B:[FORCE_END:{SIDE == 1 ? 2 # 1}]@[降伏する]@/B@@/C@")
    ENDIF
ELSE
    CALL CC_PRINT(@"@C:{カラー_注釈}@ -左クリックでオート解除@/C@")
    CALL CC_PRINT("")
    CALL CC_PRINT("")
    CALL CC_PRINT("")
ENDIF
[IF_DEBUG]
CALL CC_PRINT(@"@C:{カラー_選択不可}@(DEBUG)@B:[FORCE_END:1]@[攻撃側勝利]@/B@ @B:[FORCE_END:2]@[防御側勝利]@/B@@/C@")
[ENDIF]

RETURN 0

;-------------------------------------------------
;入力受付処理(オート)
; RETURN 1:入力完了
;-------------------------------------------------
@CLOSE_COMBAT_INPUT_AUTO()

VARSET RESULT
VARSET RESULTS
TINPUTS CC_AUTO_INPUT_WAIT, "TIME_OVER", 0, "", 1
CLEARLINE 1

SIF RESULT:1 == 1	;左クリックでオート解除
    CC_AUTO_MODE = 0

RETURN 1

;-------------------------------------------------
;;; 自動戦闘モード(CC_AUTO_MODE)の表示名を返す式中関数
;-------------------------------------------------
@COMBAT_MODE_NAME()
#FUNCTIONS
SELECTCASE CC_AUTO_MODE_INPUT
    CASE 0
        RETURNF "通常攻撃"
    CASE 1
        RETURNF "スキル"
ENDSELECT
RETURNF "不明"

;-------------------------------------------------
;;; 自動戦闘モードの入力待ち時間(CC_AUTO_INPUT_WAIT)の表示名を返す式中関数
;-------------------------------------------------
@COMBAT_SPEED_NAME()
#FUNCTIONS
SELECTCASE CC_AUTO_INPUT_WAIT
    CASE 100
        RETURNF "2倍速"
    CASE 133
        RETURNF "1.5倍速"
    CASE 200
        RETURNF "通常"
    CASEELSE
        ;通常時の値に変換する
        CC_AUTO_INPUT_WAIT = 200
        RETURNF "通常"
ENDSELECT
RETURNF "不明"

;-------------------------------------------------
; スキルの使用可否判定
;-------------------------------------------------
@CLOSE_COMBAT_SKILL_CAN_CAST(CHARA_DID, SKILL_DEF_NAME, SKILL_SLOT_IDX)
#DIM  CHARA_DID
#DIMS SKILL_DEF_NAME
#DIM  SKILL_SLOT_IDX
;キャラ
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC F_COL
#DIMS DYNAMIC BTN_ID
#DIMS DYNAMIC SKILL_NAME
#DIMS DYNAMIC STATE
;武器
#DIM  DYNAMIC WEAPON_DID
#DIMS DYNAMIC _DIC_WPN_SKILL
#DIMS DYNAMIC MEM_SKILL_DEF_LIST, VARSIZE("SKILL_DEF_LIST")
#DIM  DYNAMIC IS_WPN_SKILL
;スキル使用可否判定
#DIM  SKILL_SLOT_DID
#DIM  DYNAMIC SKILL_COOLTIME
#DIM  DYNAMIC NOT_CASTABLE
#DIMS DYNAMIC DIC_REQITEM_TOCAST
#DIMS DYNAMIC DIC_REQTOKEN_TOCAST
#DIMS DYNAMIC REQ_ITEM_NAME
#DIM  DYNAMIC REQ_ITEM_NUM
#DIM  DYNAMIC GENRE
#DIM  DYNAMIC RATE
#DIM  DYNAMIC SKILL_LV
#DIMS DYNAMIC COSTS
#DIM  DYNAMIC FACTION
#DIM  ITER_I

; DT_TOXML "CC_SKILL_SLOT"
; DEBUGPRINTFORML %RESULTS%

GENRE = スキル_ジャンル_戦闘
CHARA_ID = DT_CELL_GET("CC_ACTOR", CHARA_DID, "CHARA_ID", 1)
DT_SELECT "CC_SKILL_SLOT", @"CHARA_ID = {CHARA_ID} AND SKILL_SLOT_IDX = {SKILL_SLOT_IDX}",,SKILL_SLOT_DID
IF RESULT
    ;戦闘不能なら不可
    STATE = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "STATE", 1)%
    SIF STATE == "戦闘不能"
        RETURN -1
    ;クールタイム中なら発動不可
    RESULT:1 = DT_CELL_GET("CC_SKILL_SLOT", SKILL_SLOT_DID, "COOLTIME", 1)
    SIF RESULT:1 > 0
        RETURN 0
    SKILL_LV = DT_CELL_GET("CC_SKILL_SLOT", SKILL_SLOT_DID, "SKILL_LV", 1) > 0
    IF  DT_CELL_GET("CC_SKILL_SLOT", SKILL_SLOT_DID, "EQUIP_DID", 1) > 0
        IS_WPN_SKILL = 1
    ENDIF
ELSE

ENDIF

DIC_REQITEM_TOCAST = %GET_SKILL_DATA(SKILL_DEF_NAME, "reqItemToCast", IS_WPN_SKILL, GENRE)%
CALL SKILL_GET_EFFECT_RATE(GENRE, SKILL_DEF_NAME, SKILL_LV)
RATE = RESULT
FACTION = DT_CELL_GET("CC_ACTOR", CHARA_DID, "FACTION", 1)
;消費アイテム判定
IF DIC_REQITEM_TOCAST != "" && FACTION == CFLAG:MASTER:所属
    CALL DIC_KEYS(DIC_REQITEM_TOCAST)
    FOR ITER_I, 0, RESULT
        REQ_ITEM_NAME = %RESULTS:ITER_I%
        COSTS = %DIC_GET(DIC_REQITEM_TOCAST, RESULTS:ITER_I)%
        COSTS = %REPLACE(COSTS, "\\$RATE", @"{RATE}")%
        REQ_ITEM_NUM = TOINT(COSTS)
        SIF HO_ITEM_STOCK:GETVAR(REQ_ITEM_NAME) < REQ_ITEM_NUM
            RETURN -1
    NEXT
ENDIF
;消費トークン判定
CALL CC_CHECK_REQTOKEN_TOCAST(CHARA_DID, SKILL_DEF_NAME, GENRE, IS_WPN_SKILL)
SIF !RESULT
    RETURN -1
;その他固有の判定
CALL CC_CHECK_REQFUNC_TOCAST(CHARA_DID, SKILL_DEF_NAME, GENRE, IS_WPN_SKILL)
SIF !RESULT
    RETURN -1

RETURN 1

;要求トークンを満たしているか判定
@CC_CHECK_REQTOKEN_TOCAST(CHARA_DID, SKILL_DEF_NAME, GENRE, IS_WPN_SKILL = 0)
#DIM  CHARA_DID
#DIM  GENRE
#DIMS SKILL_DEF_NAME
#DIM  IS_WPN_SKILL
#DIMS DYNAMIC DIC_REQTOKEN_TOCAST
#DIMS DYNAMIC REQ_ITEM_NAME
#DIMS DYNAMIC COSTS
#DIMS DYNAMIC SUBCATEGORY
#DIM  DYNAMIC REQ_ITEM_NUM
#DIM  DYNAMIC SKILL_LV
#DIM  DYNAMIC RATE
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC IS_PLAYABLE
#DIMS DYNAMIC ENEMY_SKILL
#DIM  ITER_I

CHARA_ID = DT_CELL_GET("CC_ACTOR", CHARA_DID, "CHARA_ID", 1)
IS_PLAYABLE = DT_CELL_GET("CC_ACTOR", CHARA_DID, "IS_PLAYABLE", 1)
IF IS_PLAYABLE
    CALL SKILL_GET_LEVEL(CHARA_ID, GENRE, SKILL_DEF_NAME)
    SKILL_LV = RESULT
    CALL SKILL_GET_EFFECT_RATE(GENRE, SKILL_DEF_NAME, SKILL_LV)
    RATE = RESULT
ELSE
    SUBCATEGORY = %GET_SKILL_DATA(SKILL_DEF_NAME, "subcategory",,スキル_ジャンル_戦闘)%
    IF SUBCATEGORY == "ACTIVE"
        ENEMY_SKILL = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_ACTIVE_SKILL", 1)%
        SKILL_LV = TOINT(DIC_GET(ENEMY_SKILL, SKILL_DEF_NAME))
    ELSE
        ENEMY_SKILL = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_PASSIVE_SKILL", 1)%
        SKILL_LV = TOINT(DIC_GET(ENEMY_SKILL, SKILL_DEF_NAME))
    ENDIF
    CALL SKILL_GET_EFFECT_RATE(GENRE, SKILL_DEF_NAME, SKILL_LV)
    RATE = RESULT
ENDIF
DIC_REQTOKEN_TOCAST = %GET_SKILL_DATA(SKILL_DEF_NAME, "reqTokenToCast",IS_WPN_SKILL, GENRE)%
SIF DIC_REQTOKEN_TOCAST == ""
    RETURN -1
CALL DIC_KEYS(DIC_REQTOKEN_TOCAST)
FOR ITER_I, 0, RESULT
    REQ_ITEM_NAME = %RESULTS:ITER_I%
    COSTS = %DIC_GET(DIC_REQTOKEN_TOCAST, RESULTS:ITER_I)%
    COSTS = %REPLACE(COSTS, "\\$RATE", @"{RATE}")%
    REQ_ITEM_NUM = TOINT(COSTS)
    SIF CC_SP_TOKEN_NUM(CHARA_DID, REQ_ITEM_NAME) < REQ_ITEM_NUM
        RETURN 0
NEXT
RETURN 1

;固有に実装された要求判定関数の結果を見て判定
@CC_CHECK_REQFUNC_TOCAST(CHARA_DID, SKILL_DEF_NAME, GENRE, IS_WPN_SKILL = 0)
#DIM  CHARA_DID
#DIM  GENRE
#DIMS SKILL_DEF_NAME
#DIM  IS_WPN_SKILL
#DIMS DYNAMIC REQFUNC_NAME

REQFUNC_NAME = %GET_SKILL_DATA(SKILL_DEF_NAME, "reqFuncToCast",IS_WPN_SKILL, GENRE)%
TRYCCALLFORM %REQFUNC_NAME%(CHARA_DID, SKILL_DEF_NAME, IS_WPN_SKILL)
    RETURN RESULT
CATCH
    RETURN 1
ENDCATCH

;-------------------------------------------------
; 手動ターゲット選択処理(単体)
;-------------------------------------------------
@CLOSE_COMBAT_TARGET_SELECT(ACTOR_DID, SIDE, NO_MESSAGE = 0)
#DIM ACTOR_DID
#DIM SIDE
#DIM NO_MESSAGE
#DIM DYNAMIC CHARA_ID
#DIM DYNAMIC CAND_TARGET_DID, CC_MAX_MEMBER_NUM
#DIM DYNAMIC TARGET_ACTOR_DID
#DIM DYNAMIC IS_PLAYABLE
CHARA_ID = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "CHARA_ID", 1)
IS_PLAYABLE = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "IS_PLAYABLE", 1)

IF !CC_AUTO_MODE && IS_PLAYABLE
    WHILE CC_MULTI_TARGET_LIST == ""
        IF !NO_MESSAGE
            CALL CC_PRINT(@"◆ %ANAME(CHARA_ID)%の行動ターン ◆")
            CALL CC_PRINT("スキルの対象キャラを選択してください")
            CALL CC_PRINT("")
        ENDIF
        CALL CLOSE_COMBAT_DRAW_WINDOW(ACTOR_DID, @"[TARGET_SELECT:{SIDE}]")
    WEND
    TARGET_ACTOR_DID = TOINT(LIST_GET(CC_MULTI_TARGET_LIST, 0))
ELSE
    IF SIDE > -1
        DT_SELECT "CC_ACTOR", @"SIDE = {SIDE} AND STATE <> '戦闘不能'",,CAND_TARGET_DID
    ELSE
        DT_SELECT "CC_ACTOR", @"STATE <> '戦闘不能'",,CAND_TARGET_DID
    ENDIF
    TARGET_ACTOR_DID = CAND_TARGET_DID:(RAND:RESULT)
ENDIF

RETURN TARGET_ACTOR_DID

;-------------------------------------------------
; キャラ選択用オーバーレイボタン
; TARGET_SIDE = 1, 攻撃側のみ描画
; TARGET_SIDE = 0, 防御側のみ描画
; TARGET_SIDE = -1, 全メンバー
;-------------------------------------------------
@CLOSE_COMBAT_DRAW_TARGET_SELECT_BTN_OVERLAY(SIDE)
#DIM SIDE
#DIM DYNAMIC MEM_CNT
#DIM DYNAMIC ACTOR_DID, CC_MAX_MEMBER_NUM
#DIM CONST BTN_WIDTH = 3500
#DIM CONST BTN_HEIGHT = 750
;メンバーリストにオーバーレイされるキャラ選択ボタン

;攻撃側
IF SIDE == 1 || SIDE == -1
    MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = 1",, ACTOR_DID)
    FOR LOCAL, 0, MEM_CNT
        SIF DT_CELL_GETS("CC_ACTOR", ACTOR_DID:LOCAL, "STATE", 1) == "戦闘不能"
            CONTINUE
        ;キャラ選択ボタン
        CC_MEM_SERECT_BTN_SRC:LOCAL '= @"<button value='[TARGET_ACTOR_DID:{ACTOR_DID:LOCAL}]'><img src='MEM_SELECT_BTN_{LOCAL}' srcb='MEM_SELECT_BTN_SRCB_{LOCAL}' width = '{BTN_WIDTH}' height = '{BTN_HEIGHT}'></button>"
        IF CC_MEM_SERECT_BTN_SRC:LOCAL != ""
            HTML_PRINT @"<div rect='200, {-5600 + (BTN_HEIGHT * LOCAL)}, {BTN_WIDTH}, {BTN_HEIGHT}' depth='-1'>%CC_MEM_SERECT_BTN_SRC:LOCAL%</div>", 1
        ENDIF
    NEXT
    ;防御側
ELSEIF SIDE == 0 || SIDE == -1
    MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = 0",, ACTOR_DID)
    FOR LOCAL, 0, MEM_CNT
        SIF DT_CELL_GETS("CC_ACTOR", ACTOR_DID:LOCAL, "STATE", 1) == "戦闘不能"
            CONTINUE
        ;キャラ選択ボタン
        CC_MEM_SERECT_BTN_SRC:LOCAL '= @"<button value='[TARGET_ACTOR_DID:{ACTOR_DID:LOCAL}]'><img src='MEM_SELECT_BTN_{LOCAL}' srcb='MEM_SELECT_BTN_SRCB_{LOCAL}' width = '{BTN_WIDTH}' height = '{BTN_HEIGHT}'></button>"
        IF CC_MEM_SERECT_BTN_SRC:LOCAL != ""
            HTML_PRINT @"<div rect='4700, {-5600 + (BTN_HEIGHT * LOCAL)}, {BTN_WIDTH}, {BTN_HEIGHT}' depth='-1'>%CC_MEM_SERECT_BTN_SRC:LOCAL%</div>", 1
        ENDIF
    NEXT
ENDIF

@CLOSE_COMBAT_SETUP_SPRITE()
#DIM ITER_I
#DIM ITER_J

;GUI用の矩形SPRITEを準備
GCREATE CC_BTN_RECT1_GID, 20, 20
GCREATE CC_BTN_RECT2_GID, 20, 20
GSETBRUSH CC_BTN_RECT1_GID, 0x00000000 + カラー_シアン
GSETBRUSH CC_BTN_RECT2_GID, 0x66000000 + カラー_シアン
GFILLRECTANGLE CC_BTN_RECT1_GID, 0, 0, 20, 20
GFILLRECTANGLE CC_BTN_RECT2_GID, 0, 0, 20, 20

FOR ITER_I, 0, CC_MAX_MEMBER_NUM
    SPRITECREATE @"MEM_SELECT_BTN_{ITER_I}", CC_BTN_RECT1_GID
    SPRITECREATE @"MEM_SELECT_BTN_SRCB_{ITER_I}", CC_BTN_RECT2_GID
NEXT

CALL CLOSE_COMBAT_SETUP_SPRITE_TOKEN

@CLOSE_COMBAT_SETUP_SPRITE_TOKEN()
;トークンアイコン表示用
#DIM TOKEN_TYPE_NUM
#DIM TOKEN_DID, SP_TOKEN_MAX_TYPE
#DIM PARTITION
#DIM CONST SPRITE_WIDTH = 150

TOKEN_TYPE_NUM = DT_SELECT("SP_TOKEN_PARAMS",,,TOKEN_DID)

;分割数の決定。
PARTITION = 1
WHILE 1
    SIF TOKEN_TYPE_NUM <= PARTITION * PARTITION
        BREAK
    PARTITION ++
WEND

GCREATE CC_TOKEN_ICONS_GID, PARTITION * SPRITE_WIDTH, PARTITION * SPRITE_WIDTH
GSETFONT CC_TOKEN_ICONS_GID, "game-icons", SPRITE_WIDTH, 0
GSETPEN CC_TOKEN_ICONS_GID, 0x00000000, 0

VARI COLUMN
VARI ROW
LOCAL = 0
VARI LAYER_NUM
VARI ICON_COLOR
VARI UNICODE_ICON
VARI I
FOR ROW, 0, PARTITION
    FOR COLUMN, 0, PARTITION
        LAYER_NUM = LIST_COUNT(DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "UNICODE_ICON", 1))
        FOR I, 0, LAYER_NUM
            UNICODE_ICON = LIST_GETINT(DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "UNICODE_ICON", 1), I)
            ICON_COLOR = LIST_GETINT(DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "ICON_COLOR", 1), I)
            GSETBRUSH CC_TOKEN_ICONS_GID, 0xFF000000 + ICON_COLOR
            GDRAWTEXT CC_TOKEN_ICONS_GID, @"%UNICODE(UNICODE_ICON)%", SPRITE_WIDTH * COLUMN, SPRITE_WIDTH * ROW
        NEXT
        SPRITECREATE @"CC_ICON_TOKEN_{TOKEN_DID:LOCAL}", CC_TOKEN_ICONS_GID, SPRITE_WIDTH * COLUMN, SPRITE_WIDTH * ROW, SPRITE_WIDTH, SPRITE_WIDTH
        LOCAL ++
        SIF LOCAL >= TOKEN_TYPE_NUM
            GOTO DRAW_END
    NEXT
NEXT
$DRAW_END

;PRINTFORMW ICON_TEST:
;FOR LOCAL, 0, TOKEN_TYPE_NUM
;	LOCALS += @"<img src='CC_ICON_TOKEN_{TOKEN_DID:LOCAL}' srcb='' height='150'>"
;NEXT
;HTML_PRINT LOCALS
;PRINTW

;-------------------------------------------------
;;; 戦闘で使用するスプライトの破棄
;;; 終了時に初期化すると都合の悪いスプライトは @CC_INIT() 実行時にAT_INIT = 1 として初期化する
;-------------------------------------------------
@CLOSE_COMBAT_DISPOSE_SPRITE(AT_INIT = 0)
#DIM AT_INIT
#DIM ITER_I

;戦闘開始時
IF AT_INIT
    GDISPOSE CC_TOKEN_ICONS_GID
ELSE ;戦闘終了時
    ;スプライト破棄
    FOR ITER_I, 0, CC_MAX_MEMBER_NUM
        SPRITEDISPOSE @"MEM_SELECT_BTN_{ITER_I}"
        SPRITEDISPOSE @"MEM_SELECT_BTN_SRCB_{ITER_I}"
    NEXT
    GDISPOSE CC_BTN_RECT1_GID
    GDISPOSE CC_BTN_RECT2_GID
ENDIF
;-------------------------------------------------
;参加キャラがNPCのみか判定
;-------------------------------------------------
@CLOSE_COMBAT_GET_ACTOR_NPC_ONLY()
#FUNCTION
#DIM MEM_CNT
#DIM IDX, CC_MAX_MEMBER_NUM
#DIM L_CNT
#DIM ACTOR_CHARA_ID
#DIM ACTOR_NPC_ONLY

ACTOR_NPC_ONLY = 1
MEM_CNT = DT_SELECT("CC_ACTOR",,,IDX)
FOR L_CNT, 0, MEM_CNT
    ACTOR_CHARA_ID = DT_CELL_GET("CC_ACTOR", IDX:L_CNT, "CHARA_ID", 1)
    IF ACTOR_CHARA_ID >= 0 && CFLAG:ACTOR_CHARA_ID:所属 == 所属_プレイヤー
        ACTOR_NPC_ONLY = 0
        BREAK
    ENDIF
NEXT
RETURNF ACTOR_NPC_ONLY

@CLOSE_COMBAT_DRAW_MEMBER_WINDOW(SIDE, ACTOR_DID)
#DIM  SIDE
#DIM  ACTOR_DID
#DIM  DYNAMIC WND_ID
#DIM  DYNAMIC WND_ID_MEM, CC_MAX_MEMBER_NUM
#DIM  DYNAMIC MEM_CNT
#DIM  DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIM  DYNAMIC CHARA_ID
#DIMS DYNAMIC BTN_ID
#DIMS DYNAMIC STATE
#DIM  DYNAMIC TOKEN_COUNT
#DIMS DYNAMIC TOOLTIP

#DIM CONST TOTAL_WND_WIDTH = 166
#DIM CONST LIST_WND_WIDTH = 80
#DIM CONST LIST_WND_HEIGHT = 42
#DIM CONST BOTTOM_WND_HEIGHT = 10
#DIM CONST WIDTH = 3600
#DIM CONST HEIGHT = 700
#DIM CONST MARGIN = 50
#DIM DYNAMIC L_CNT

#DIMS DYNAMIC WINDOW_STR
#DIMS DYNAMIC HEADER
#DIMS DYNAMIC COLUMN, 7
#DIM  DYNAMIC BORDER_COLOR
#DIM  DYNAMIC POS_X
#DIM  DYNAMIC POS_Y
#DIM  CONST   POS_X_ATK = 200
#DIM  CONST   POS_X_DEF = 4700

#DIM ITER_J
VARSET CC_MEM_SERECT_BTN_SRC

;外枠
BORDER_COLOR = カラー_白
IF SIDE == 1
    POS_X = POS_X_ATK
    {
        WINDOW_STR += @"<div rect='{POS_X - 50}, {POS_Y - 50}, {WIDTH + 100 + 300}, {(HEIGHT + MARGIN) * 6 + 20}' depth='0' border = '1px' bcolor = '#%CVH(BORDER_COLOR)%'></div>"
    }
ELSE
    POS_X = POS_X_DEF
    {
        WINDOW_STR += @"<div rect='{POS_X - 50 - 300}, {POS_Y - 50}, {WIDTH + 100 + 300}, {(HEIGHT + MARGIN) * 6 + 20}' depth='0' border = '1px' bcolor = '#%CVH(BORDER_COLOR)%'></div>"
    }
ENDIF

;メンバーリスト
MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {SIDE}", "PLACEMENT ASC", IDX)
FOR LOCAL, 0, MEM_CNT
    L_CNT = 0
    ;ポジション算出
    IF SIDE == 1
        POS_X = POS_X_ATK
    ELSE
        POS_X = POS_X_DEF
    ENDIF
    POS_Y = (HEIGHT + MARGIN) * LOCAL

    ;状態取得
    STATE = %DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "STATE", 1)%

    ;名前
    ;LOCALS '= @"({DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "PLACEMENT", 1)}) <b>%DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "CHARA_NAME", 1)%</b>"
    LOCALS '= @"<b>%DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "CHARA_NAME", 1)%</b>"
    IF STATE == "戦闘不能"
        LOCALS '= @"<font color='#%CVH(カラー_選択不可)%'>%LOCALS%</font>"
    ENDIF

    ;トークン obsolete
    [SKIPSTART]
    FOR ITER_J, 0, VARSIZE("CC_TOKEN_NAME_ENG")
        TOKEN_COUNT = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, CC_TOKEN_NAME_ENG:ITER_J, 1)
        IF TOKEN_COUNT > 0
            TOOLTIP '= ""
            IF EXISTVAR(@"CC_TOKEN_TOOLTIP_%CC_TOKEN_NAME_ENG:ITER_J%")
                TOOLTIP = %GETVARS(@"CC_TOKEN_TOOLTIP_%CC_TOKEN_NAME_ENG:ITER_J%")%
                ;食事効果
            ELSEIF CC_TOKEN_NAME_ENG:ITER_J == "MEAL_EFFECT"
                VARI MEAL_EFFECT_ID
                MEAL_EFFECT_ID = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "MEAL_EFFECT_ID", 1)
                TRYCALLFORMF GET_INFO_INSTANT_BUFF_{MEAL_EFFECT_ID}("CC_TOOLTIP")
                TOOLTIP = %RESULTS%
            ENDIF
            ;トークン数を表示する必要がないトークン(0or1しかないステータス)
            IF GROUPMATCH(CC_TOKEN_NAME_ENG:ITER_J, "CHEST_EXPOSE", "GENITAL_EXPOSE")
                LOCALS += @"<nonbutton title = '%TOOLTIP%'>【%CC_TOKEN_NAME_JP:ITER_J%】</nonbutton>"
            ELSE
                LOCALS += @"<nonbutton title = '%TOOLTIP%'>【%CC_TOKEN_NAME_JP:ITER_J%:{TOKEN_COUNT}】</nonbutton>"
            ENDIF
        ENDIF
    NEXT
    [SKIPEND]
    ;特殊トークン
    LOCALS += CLOSE_COMBAT_DRAW_MEMBER_WINDOW_PREPARE_SP_TOKEN_TEXT(IDX:LOCAL)

    ; CALL WndMgr_WindowTitle(WND_ID_MEM:LOCAL, LOCALS)
    COLUMN:L_CNT = %LOCALS%
    L_CNT ++

    ;体力バー
    LOCALS '= COLOR_BAR_H(DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "HP", 1), DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "MAX_HP", 1), 18, 0xEE6600, 0xFFFF98, 0x000000, 1)
    COLUMN:L_CNT = %LOCALS%

    ;行動状態
    IF STATE == "戦闘不能"
        LOCALS '= @"　　@C:{カラー_オレンジ}@%"【"+ TR(STATE) + "】", 6, LEFT%@/C@"
    ELSE
        LOCALS '= @"　　@C:{カラー_注釈}@%"【"+ TR(STATE) + "】", 6, LEFT%@/C@"
    ENDIF
    COLUMN:L_CNT += CONV_TAG2H(LOCALS)
    L_CNT ++

    ;CALL WndMgr_TextSet(WND_ID_MEM:LOCAL, L_CNT++, LOCALS)
    ;パラメータ
    LOCALS '= @"@C:{カラー_注釈}@" + TR("攻撃") + @":{DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "ATTACK", 1), 6, LEFT}@/C@"
    LOCALS += @"@C:{カラー_注釈}@" + TR("魔力") + @":{DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "MAG", 1), 6, LEFT}@/C@"
    LOCALS += @"@C:{カラー_注釈}@" + TR("防御") + @":{DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "DEFENCE", 1), 6, LEFT}@/C@"
    LOCALS += @"@C:{カラー_注釈}@" + TR("行動") + @":{DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "AGILITY", 1), 6, LEFT}@/C@"
    LOCALS += @"@C:{カラー_注釈}@" + TR("軽減") + @":{DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "ARMOR", 1), 6, LEFT}@/C@"
    LOCALS += @"@C:{カラー_注釈}@" + TR("選敵") + @":%WPN_脅威選定文字列:DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "TARGETING", 1), 10, LEFT%@/C@"
    COLUMN:L_CNT = %CONV_TAG2H(LOCALS)%
    L_CNT ++

    ;アクティブスキルスロット
    CALL CLOSE_COMBAT_DRAW_SKILL_BUTTON(WND_ID_MEM:LOCAL, IDX:LOCAL)
    COLUMN:L_CNT = %RESULTS:0%
    L_CNT ++
    COLUMN:L_CNT = %RESULTS:1%
    L_CNT ++
    COLUMN:L_CNT = %RESULTS:2%

    ;演出処理
    IF STATE == "攻撃" || STATE == "再行動"
        BORDER_COLOR = カラー_緑
        IF SIDE == 0
            POS_X -= 300
        ELSE
            POS_X += 300
        ENDIF
    ELSEIF STATE == "行動不能"
        BORDER_COLOR = カラー_黄
    ELSEIF IDX:LOCAL == ACTOR_DID
        BORDER_COLOR = カラー_緑
    ELSEIF DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "EFFECT", 1) == "被ダメージ"
        BORDER_COLOR = カラー_オレンジ
        DT_CELL_SET "CC_ACTOR", IDX:LOCAL, "EFFECT", "", 1
    ELSEIF DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "EFFECT", 1) == "増援"
        BORDER_COLOR = カラー_シアン
        DT_CELL_SET "CC_ACTOR", IDX:LOCAL, "EFFECT", "", 1
    ELSEIF STATE == "行動済"
        BORDER_COLOR = カラー_選択不可
    ELSEIF STATE == "戦闘不能"
        BORDER_COLOR = カラー_選択不可
    ELSE
        BORDER_COLOR = カラー_白
    ENDIF

    {
        WINDOW_STR +=
            @"<div rect='{POS_X}, {POS_Y}, {WIDTH}, {HEIGHT}' depth='0' border = '1px' bcolor = '#%CVH(BORDER_COLOR)%' padding='2px'>"
            + @"%COLUMN:0%<br>"
            + @"%COLUMN:1%<br>"
            + @"%COLUMN:2%<br>"
            + @"%COLUMN:3%<br>"
            + @"%COLUMN:4%<br>"
            + @"%COLUMN:5%<br>"
            + @"%COLUMN:6%<br>"
            + @"</div>"
    }
NEXT

HTML_PRINT WINDOW_STR, 1

;-------------------------------------------------
;;; 戦闘後に空腹度を一律プラスする処理
;;; 基本100、HUNGRYで倍率指定
;-------------------------------------------------
@CLOSE_COMBAT_EXIT_INCREASE_HUNGER_LEVEL(HUNGRY = 1)
#DIM HUNGRY
#DIM DYNAMIC CHARA_ID
#DIM DYNAMIC L_CNT
;パーティメンバーの空腹度を+100する
FOR L_CNT, 0, QST_PARTYNUM
    CHARA_ID = TOINT(LIST_GET(_LIST_QST_PARTY, L_CNT))
    TCVAR:CHARA_ID:空腹度 += (100 * HUNGRY)
NEXT

;-------------------------------------------------
;;; xmlで定義するトークンの表示用テキスト生成
;-------------------------------------------------
@CLOSE_COMBAT_DRAW_MEMBER_WINDOW_PREPARE_SP_TOKEN_TEXT(IDX)
#FUNCTIONS
#DIM IDX

#DIMS TEXT
#DIM  TOKEN_COUNT
#DIM TOKEN_DID, SP_TOKEN_MAX_TYPE
#DIM TOKEN_TYPE_NUM
#DIMS ICON
#DIMS TOKEN_NAME
#DIMS TOOLTIP
TEXT '= ""

TOKEN_TYPE_NUM = DT_SELECT("SP_TOKEN_PARAMS",,,TOKEN_DID)
FOR LOCAL, 0, TOKEN_TYPE_NUM
    TOKEN_COUNT =  DT_CELL_GET("CC_SP_TOKEN_NUM", IDX, DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "TOKEN_DEF_NAME", 1), 1)
    SIF TOKEN_COUNT == 0
        CONTINUE

    TOKEN_NAME '= DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "TOKEN_NAME", 1)
    TOOLTIP '= DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "TOOLTIP", 1)

    IF DT_CELL_GETS("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "TOKEN_DEF_NAME", 1) == "MEAL_EFFECT"
        TRYCALLFORMF GET_INFO_INSTANT_BUFF_{DT_CELL_GET("CC_ACTOR", IDX, "MEAL_EFFECT_ID", 1)}("CC_TOOLTIP")
        TOOLTIP = %RESULTS%
    ENDIF

    IF DT_CELL_GET("SP_TOKEN_PARAMS", TOKEN_DID:LOCAL, "IGNORE_QUANTITY", 1) == 1
        TEXT += " " + @"<nonbutton title = '%TOKEN_NAME%\n%TOOLTIP%'><img src='CC_ICON_TOKEN_{TOKEN_DID:LOCAL}' srcb='' height='150' ypos='-20'></nonbutton>"
    ELSE
        TEXT += " " + @"<nonbutton title = '%TOKEN_NAME%\n%TOOLTIP%'><img src='CC_ICON_TOKEN_{TOKEN_DID:LOCAL}' srcb='' height='150' ypos='-20'>{TOKEN_COUNT}</nonbutton>"
    ENDIF

NEXT
RETURNF TEXT

[SKIPSTART]
FOR LOCAL, 1, DT_COLUMN_NAMES("CC_SP_TOKEN_NUM")
	TOKEN_NAME = %RESULTS:LOCAL%

	TOKEN_COUNT = DT_CELL_GET("CC_SP_TOKEN_NUM", IDX, TOKEN_NAME, 1)
	SIF TOKEN_COUNT == 0
		CONTINUE
	DISPLAY_NAME '= ""
	TOOLTIP '= ""
	IGNORE_QUANTITY = 0
	RESULTS '= ""
	XML_GET XMLID_TOKEN, @"//defname[@parentname='%TOKEN_NAME%']", _XML_TOKEN, 3
	XML_GET _XML_TOKEN, @"//tokenname", DISPLAY_NAME, 1
	XML_GET _XML_TOKEN, @"//tooltip", TOOLTIP, 1
	TOOLTIP = %REPLACE(TOOLTIP, "\\[\\$NUM\\]", @"{TOKEN_COUNT}")%
	XML_GET _XML_TOKEN, @"//ignoreQuantity", RESULTS, 1
	IGNORE_QUANTITY = TOINT(RESULTS)
	IF IGNORE_QUANTITY == 1
		TEXT += @"<nonbutton title = '%TOOLTIP%'>【%DISPLAY_NAME%】</nonbutton>"
	ELSE
		TEXT += @"<nonbutton title = '%TOOLTIP%'>【%DISPLAY_NAME%:{TOKEN_COUNT}】</nonbutton>"
	ENDIF
NEXT
[SKIPEND]


code:
;-------------------------------------------------
;戦闘開始時に発動する効果の処理
;-------------------------------------------------
@CLOSE_COMBAT_OPENING_ACTION
#DIMS ACTOR_LIST, CC_MAX_MEMBER_NUM + 1
#DIM  DYNAMIC ACTOR_DID
#DIM  DYNAMIC TARGET_DID

CALL CLOSE_COMBAT_SET_ORDER(ACTOR_LIST)
CC_AUTO_MODE = 1
FOR LOCAL, 0, CC_MAX_MEMBER_NUM + 1
	SIF ACTOR_LIST:LOCAL == "-1"
		BREAK
	DEBUGPRINTFORML ACTOR_LIST:{LOCAL} = %ACTOR_LIST:LOCAL%

	ACTOR_DID = TOINT(DIC_GET(ACTOR_LIST:LOCAL, "ACTOR_DID"))
	CALL CLOSE_COMBAT_SET_TARGET(ACTOR_DID)
	TARGET_DID = RESULT
	CALL CC_EXEC_PASSIVE_SKILL("OPENING", ACTOR_DID, TARGET_DID)

	CALL CLOSE_COMBAT_DRAW_WINDOW(ACTOR_DID)

NEXT

CC_AUTO_MODE = 0

repo_name: pervysquirrelz/erafl

license: unknown


code:
#DIM CONST SP_TOKEN_MAX_TYPE = 100	;特殊トークンの最大種類
#DIM CONST SP_TOKEN_MAX_SKILL = 10	;特殊トークン1個あたりのスキル最大数
#DIM CONST SP_TOKEN_MAX_MODIFIER = 10	;特殊トークン1個あたりの補正値最大数
#DIM CONST SP_TOKEN_MAX_LAYER = 5	;トークン用アイコンの最大レイヤー数

;処理順の定義
;未定義のトークンはこの後にXML上の順番で処理される
{
    #DIMS CONST TOKEN_PRIORITY =
        "POISON"
        ,"BURN"
        ,"BINDINGTRAP"
        ,"BEARTRAP"
        ,"ORGASM"
        ,"STUN"
        ,"SLEEP"
        ,"ESTRUS"
}


code:
;-------------------------------------------------
;攻撃側、防御側決定
;RESULT:0 攻撃側リスト(MEM_LIST1)
;RESULT:1 防御側リスト(MEM_LIST2)
;ACTOR, ACTOR番のキャラが行動する
;-------------------------------------------------
; #region @CLOSE_COMBAT_SET_TARGET
@CLOSE_COMBAT_SET_TARGET(ACTOR_DID)
#DIM ACTOR_DID
#DIM  DYNAMIC ACTOR_CHARA_ID
#DIM  DYNAMIC TARGET_DID
#DIM  DYNAMIC TARGETING
#DIM  DYNAMIC TARGETING_SIDE
#DIMS DYNAMIC TARGETING_TOKEN_NAME
#DIM  DYNAMIC DECIDED_TARGETING_SIDE
#DIM  DYNAMIC COLLATERAL_TARGET_TYPE
#DIM  DYNAMIC COLLATERAL_TARGET_RANGE
#DIM  DYNAMIC TARGETING_OVERRIDE_FLAG
#DIM  DYNAMIC HATE_RATE
#DIM  DYNAMIC HP
#DIM  DYNAMIC MAX_HP
#DIM  DYNAMIC ATTACK
#DIM  DYNAMIC MAG
#DIM  DYNAMIC SIDE
#DIM  DYNAMIC CHARA_ID
#DIM  DYNAMIC IS_PLAYABLE
#DIM  CONST   HIGH_VALUE = 999999999999

#DIM  DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIMS DYNAMIC TAC_LIST, CC_MAX_MEMBER_NUM

#DIM  MAX_TARGET
#DIM  DYNAMIC MEM_CNT
#DIM  DYNAMIC TGT_IDX
#DIMS DYNAMIC _LIST_TARGET
#DIM  DYNAMIC PREV_THREAT_POINT
#DIM  DYNAMIC THREAT_POINT
#DIM  DYNAMIC IS_ASCEND

#DIMS DYNAMIC _XML_SKILL
#DIMS DYNAMIC SKILL_DEF_NAME
#DIMS DYNAMIC ACTOR_SKILL_DEF_LIST, VARSIZE("SKILL_DEF_LIST")
#DIM  DYNAMIC ACTOR_SELECT_SLOT = -1

CC_MULTI_TARGET_LIST '= ""
CC_MULTI_TARGET_ATTACKED_COUNT = 0
CC_全体攻撃フラグ = 0

IS_PLAYABLE = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "IS_PLAYABLE", 1)
;キャラクターにセットされている脅威選定ルーチンを取得
;-------------------------------------------------
TARGETING = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "TARGETING", 1)
;アクティブスキルによる脅威選定ルーチンの上書き判定
ACTOR_CHARA_ID =  DT_CELL_GET("CC_ACTOR", ACTOR_DID, "CHARA_ID", 1)
IF IS_PLAYABLE
    ACTOR_SELECT_SLOT = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "SELECTED_SKILL_SLOT", 1)
    IF ACTOR_SELECT_SLOT != -1
        CALL CC_EXEC_ACTIVE_SKILL("TARGETING", ACTOR_DID)
        IF RESULT
            TARGETING = RESULT:1
            TARGETING_SIDE = RESULT:2
            TARGETING_OVERRIDE_FLAG = 1
            TARGETING_TOKEN_NAME = %RESULTS%
        ENDIF
        COLLATERAL_TARGET_TYPE = RESULT:3
        COLLATERAL_TARGET_RANGE = RESULT:4
    ENDIF
ELSE
    SKILL_DEF_NAME = %DT_CELL_GETS("CC_ACTOR", ACTOR_DID, "ENEMY_SELECTED_SKILL", 1)%
    IF SKILL_DEF_NAME != ""
        CALL CC_EXEC_ACTIVE_SKILL("TARGETING", ACTOR_DID,, SKILL_DEF_NAME)
        IF RESULT
            TARGETING = RESULT:1
            TARGETING_SIDE = RESULT:2
            TARGETING_OVERRIDE_FLAG = 1
            TARGETING_TOKEN_NAME = %RESULTS%
        ENDIF
        COLLATERAL_TARGET_TYPE = RESULT:3
        COLLATERAL_TARGET_RANGE = RESULT:4
    ENDIF
ENDIF

;攻撃対象側を決定
;TARGETING_SIDEの値は0 = 相手
;TARGETING_SIDEの値は1 = 味方
;TARGETING_SIDEの値は-1 = 全員(未実装)
;-------------------------------------------------
SIDE = DT_CELL_GET("CC_ACTOR", ACTOR_DID, "SIDE", 1)
IF TARGETING_SIDE == 1
    DECIDED_TARGETING_SIDE = SIDE
ELSE
    DECIDED_TARGETING_SIDE = SIDE == 0 ? 1 # 0
ENDIF

IF TARGETING == WPN_脅威選定_選択
    CALL CLOSE_COMBAT_TARGET_SELECT(ACTOR_DID, DECIDED_TARGETING_SIDE)
    TARGET_DID = RESULT

    SIF COLLATERAL_TARGET_TYPE != WPN_COLLATERAL_TARGET_NONE && COLLATERAL_TARGET_RANGE > 0
        CALL CLOSE_COMBAT_SET_COLLATERAL_DAMAGE_TARGET(TARGET_DID, COLLATERAL_TARGET_TYPE, COLLATERAL_TARGET_RANGE)

    RETURN TARGET_DID
ENDIF

;脅威度の計算とリストの作成
;-------------------------------------------------
MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {DECIDED_TARGETING_SIDE}",, IDX)
;[挑発]持ちがいる場合は、無作為と同じ脅威選定を行う
;アクティブスキルで脅威選定が上書きされている場合はアクティブスキル側が優先される
FOR LOCAL, 0, MEM_CNT
    IF CC_SP_TOKEN_NUM(IDX:LOCAL, "PROVOKE") > 0
        {
            IF !TARGETING_OVERRIDE_FLAG
                && !GROUPMATCH(TARGETING
                ,WPN_脅威選定_全体
                ,WPN_脅威選定_性攻撃男向け
                ,WPN_脅威選定_性攻撃女向け
                )
        }
            TARGETING = WPN_脅威選定_無作為
        ENDIF
    ENDIF
NEXT

VARI SEDUCTION_LV
MAX_TARGET = 0
MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {DECIDED_TARGETING_SIDE}",, IDX)
FOR LOCAL, 0, MEM_CNT
    SIF DT_CELL_GETS("CC_ACTOR", IDX:LOCAL, "STATE", 1) == "戦闘不能"
        CONTINUE
    HATE_RATE = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "HATE_RATE", 1)
    ;<挑発>のトークン持ちは脅威度を10倍
    IF CC_SP_TOKEN_NUM(IDX:LOCAL, "PROVOKE") > 0
        HATE_RATE = HATE_RATE * 10
    ENDIF
    ;<隠蔽>のトークン持ちは脅威度を1/100倍
    IF CC_SP_TOKEN_NUM(IDX:LOCAL, "HIDE") > 0
        HATE_RATE = HATE_RATE * 1 /100
    ENDIF
    ;<突撃準備>のトークン持ちは脅威度を1/10倍
    IF CC_SP_TOKEN_NUM(IDX:LOCAL, "CHARGE_PREP") > 0
        HATE_RATE = HATE_RATE / 10
    ENDIF
    ;<昇竜>のトークン持ちは脅威度を1/10倍
    IF CC_SP_TOKEN_NUM(IDX:LOCAL, "DRAGON_RISING") > 0
        HATE_RATE = HATE_RATE / 10
    ENDIF
    HP     = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "HP", 1)
    MAX_HP = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "MAX_HP", 1)
    ATTACK = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "ATTACK", 1)
    MAG = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "MAG", 1)
    CHARA_ID = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "CHARA_ID", 1)

    HATE_RATE = LIMIT(HATE_RATE, 1, 1000)
    SELECTCASE TARGETING
        CASE WPN_脅威選定_高脅威
            THREAT_POINT = ATTACK * HATE_RATE
        CASE WPN_脅威選定_低脅威
            THREAT_POINT = HATE_RATE * 10000 / MAX(ATTACK, 1)
        CASE WPN_脅威選定_高耐久
            THREAT_POINT = MAX_HP * HATE_RATE
        CASE WPN_脅威選定_低耐久
            THREAT_POINT = HIGH_VALUE - (MAX_HP * 10000 / HATE_RATE)
        CASE WPN_脅威選定_低HP
            THREAT_POINT = HIGH_VALUE -  (HP * 10000 / HATE_RATE)
        CASE WPN_脅威選定_高割合HP
            THREAT_POINT = (HP * 10000 * HATE_RATE) / MAX_HP
        CASE WPN_脅威選定_低割合HP,
            THREAT_POINT = HIGH_VALUE -  (HP * 10000)  / (MAX_HP * HATE_RATE)
        CASE WPN_脅威選定_魔術師
            THREAT_POINT = MAG * HATE_RATE
        CASE WPN_脅威選定_トークン
            IF CC_SP_TOKEN_NUM(IDX:LOCAL, TARGETING_TOKEN_NAME) > 0
                THREAT_POINT = HATE_RATE * 15
            ELSE
                THREAT_POINT = HATE_RATE
            ENDIF
        CASE WPN_脅威選定_性攻撃男向け, WPN_脅威選定_性攻撃女向け
            SEDUCTION_LV = HAS_SKILL(CHARA_ID, "SEDUCTION", スキル_大分類_性技)
            SIF CHARA_ID == -1
                CONTINUE
            IF IS_PLAYABLE && SEDUCTION_LV < 1
                THREAT_POINT = -1
            ELSE
                THREAT_POINT = HATE_RATE
                IF RAND:2
                    THREAT_POINT = FTIMES(THREAT_POINT, 100 + (SEDUCTION_LV * 50))
                ENDIF

                SIF CC_SP_TOKEN_NUM(IDX:LOCAL, "CHEST_EXPOSE") > 0
                    THREAT_POINT *= 5
                SIF CC_SP_TOKEN_NUM(IDX:LOCAL, "GENITAL_EXPOSE") > 0
                    THREAT_POINT *= 5
                SIF CC_SP_TOKEN_NUM(IDX:LOCAL, "ESTRUS") > 0
                    THREAT_POINT *= 5
                SIF CC_SP_TOKEN_NUM(IDX:LOCAL, "ORGASM") > 0
                    THREAT_POINT *= 10
                SIF CC_SP_TOKEN_NUM(IDX:LOCAL, "STUN") > 0
                    THREAT_POINT *= 2
                IF TARGETING == WPN_脅威選定_性攻撃女向け && IS_MALE(CHARA_ID)
                    THREAT_POINT = -1
                ELSEIF TARGETING == WPN_脅威選定_性攻撃男向け && IS_FEMALE(CHARA_ID)
                    THREAT_POINT = -1
                ENDIF
            ENDIF
        CASEELSE
            THREAT_POINT = HATE_RATE
    ENDSELECT
    ;追跡トークンによる脅威選定ルーチンの上書き判定
    IF (CC_SP_TOKEN_NUM(ACTOR_DID, "TRACKING") > 0) && (CC_SP_TOKEN_NUM(IDX:LOCAL, "TARGET") > 0) && (TARGETING != WPN_脅威選定_全体)
        THREAT_POINT = __INT_MAX__      ;行動側が追跡トークン持ちかつ選敵候補が標的トークンを持っている場合、最大値を設定
        TARGETING = WPN_脅威選定_追跡    ;脅威選定を上書き
    ENDIF

    TAC_LIST:TGT_IDX = %DIC_SET(TAC_LIST:TGT_IDX, "DID", TOSTR(IDX:LOCAL))%
    TAC_LIST:TGT_IDX = %DIC_SET(TAC_LIST:TGT_IDX, "THREAT_POINT", TOSTR(THREAT_POINT))%
    TGT_IDX ++
NEXT
MAX_TARGET = TGT_IDX
TAC_LIST:(TGT_IDX) '= "-1"

; 算出した脅威度に基づくソート
;-------------------------------------------------
; SELECTCASE TARGETING
;         ;低いほど優先度が高い脅威選定は昇順ソート
;     CASE WPN_脅威選定_低耐久,WPN_脅威選定_低HP, WPN_脅威選定_低割合HP
;         CALL ARRAYSORT_DIC(TAC_LIST, "THREAT_POINT", 0)
;         IS_ASCEND = 1
;     CASEELSE
IF TARGETING != WPN_脅威選定_無作為 || TARGETING != WPN_脅威選定_全体
    CALL ARRAYSORT_DIC(TAC_LIST, "THREAT_POINT", 1)
ENDIF
; ENDSELECT

; 全体攻撃処理
;-------------------------------------------------
IF TARGETING == WPN_脅威選定_全体
    FOR LOCAL, 0, MAX_TARGET
        CC_MULTI_TARGET_LIST = %LIST_ADD(CC_MULTI_TARGET_LIST, DIC_GET(TAC_LIST:LOCAL, "DID"))%
        CC_全体攻撃フラグ = 1
    NEXT
    RETURN TARGET_DID
ENDIF

; 最終的なターゲットの選出
;-------------------------------------------------
IF MAX_TARGET == 0
    TARGET_DID = TOINT(DIC_GET(TAC_LIST:0, "DID"))
ELSE
    FOR LOCAL, 0, MAX_TARGET
        IF LOCAL == 0
            PREV_THREAT_POINT = TOINT(DIC_GET(TAC_LIST:LOCAL,  "THREAT_POINT"))
            _LIST_TARGET = %LIST_ADD(_LIST_TARGET, DIC_GET(TAC_LIST:LOCAL, "DID"))%
        ELSE
            THREAT_POINT = TOINT(DIC_GET(TAC_LIST:LOCAL,  "THREAT_POINT"))
            ;脅威度が同値のキャラがいる場合を考慮して最終的な選出リストをつくる
            IF THREAT_POINT == PREV_THREAT_POINT
                _LIST_TARGET = %LIST_ADD(_LIST_TARGET, DIC_GET(TAC_LIST:LOCAL, "DID"))%
            ELSEIF IS_ASCEND && THREAT_POINT < PREV_THREAT_POINT
                _LIST_TARGET '= ""
                _LIST_TARGET = %LIST_ADD(_LIST_TARGET, DIC_GET(TAC_LIST:LOCAL, "DID"))%
            ELSEIF !IS_ASCEND  &&  THREAT_POINT > PREV_THREAT_POINT
                _LIST_TARGET '= ""
                _LIST_TARGET = %LIST_ADD(_LIST_TARGET, DIC_GET(TAC_LIST:LOCAL, "DID"))%
            ENDIF
        ENDIF
    NEXT
    ;アクティブスキルで脅威選定ルーチンが変更されている場合は確実にそれに従う
    IF TARGETING_OVERRIDE_FLAG
        TARGET_DID = TOINT(LIST_RAND(_LIST_TARGET))
        ;脅威選定_追跡により対象が決定されている場合は、確実にそれに従う
    ELSEIF TARGETING == WPN_脅威選定_追跡
        TARGET_DID = TOINT(LIST_RAND(_LIST_TARGET))
        ;確率85%で最優先目標を狙う。同値の対象がいる場合は同値の対象からランダムに選出
    ELSEIF RAND:100 < 85 && TARGETING != WPN_脅威選定_無作為
        TARGET_DID = TOINT(LIST_RAND(_LIST_TARGET))
    ELSE
        ;上記以外は完全に無作為に選出する
        ;TARGET_DID = TOINT(DIC_GET(TAC_LIST:RAND(0,MAX_TARGET), "DID"))
        ;無作為の場合は敵視の値による重み付け抽選をおこなう
        CALL RAND_WT_INIT()
        FOR LOCAL, 0, MAX_TARGET
            ;THREAT_POINT0の場合重み付け抽選できないので1点加算
            CALL RAND_WT_SET(LOCAL, TOINT(DIC_GET(TAC_LIST:LOCAL, "THREAT_POINT")) + 1)
        NEXT
        TARGET_DID =  TOINT(DIC_GET(TAC_LIST:RAND_WT_RESULT(), "DID"))
    ENDIF
ENDIF

; [IF_DEBUG]
; DEBUGPRINTFORML -ターゲット選出------------------------------------------------
; DEBUGPRINTFORML 脅威選定:{TARGETING}
; FOR LOCAL, 0, VARSIZE("TAC_LIST")
;     SIF TAC_LIST:LOCAL == "-1"
;         BREAK
;     DEBUGPRINTFORML %TAC_LIST:LOCAL%
; NEXT
; DEBUGPRINTFORML TARGET_DID:{TARGET_DID}:%DT_CELL_GETS("CC_ACTOR", TARGET_DID, "CHARA_NAME", 1)%を選出
; DEBUGPRINTFORML TARGETING_TOKEN_NAME:%TARGETING_TOKEN_NAME%
; [ENDIF]

;該当するターゲットが一人もいない場合はスキル選択を破棄し再ターゲティング
IF !TARGET_DID && !IS_PLAYABLE
    DT_CELL_SET "CC_ACTOR", ACTOR_DID, "ENEMY_SELECTED_SKILL", "", 1
    RESTART
ENDIF

SIF COLLATERAL_TARGET_TYPE != WPN_COLLATERAL_TARGET_NONE && COLLATERAL_TARGET_RANGE > 0
    CALL CLOSE_COMBAT_SET_COLLATERAL_DAMAGE_TARGET(TARGET_DID, COLLATERAL_TARGET_TYPE, COLLATERAL_TARGET_RANGE)

RETURN TARGET_DID
; #endregion

;-------------------------------------------------
;;; 巻き添えターゲット判定
;;; - 結果は連想配列CC_COLLATERAL_DAMAGE_TARGET_MAPに入る
;;;   - KEY: 対象のDID
;;;   - VALUE: メインターゲットからの距離(絶対値)
;;; - トークンスキルによる攻撃は対応未。
;-------------------------------------------------
@CLOSE_COMBAT_SET_COLLATERAL_DAMAGE_TARGET(TARGET_DID, COLLATERAL_TARGET_TYPE, COLLATERAL_TARGET_RANGE)
#DIM TARGET_DID
#DIM COLLATERAL_TARGET_TYPE
#DIM COLLATERAL_TARGET_RANGE
#DIM SIDE
#DIM MAIN_TARGET_PLACEMENT
#DIM MEM_CNT
#DIM IDX, CC_MAX_MEMBER_NUM
#DIM INDEX

SIDE = DT_CELL_GET("CC_ACTOR", TARGET_DID, "SIDE", 1)
MAIN_TARGET_PLACEMENT = DT_CELL_GET("CC_ACTOR", TARGET_DID, "PLACEMENT", 1)
MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {SIDE}","PLACEMENT ASC", IDX)

IF !MAP_EXIST(CC_COLLATERAL_DAMAGE_TARGET_MAP)
    MAP_CREATE CC_COLLATERAL_DAMAGE_TARGET_MAP
ELSE
    MAP_CLEAR CC_COLLATERAL_DAMAGE_TARGET_MAP
ENDIF
;DEBUGPRINTFORML MAIN_TARGET_PLACEMENT {MAIN_TARGET_PLACEMENT}
FOR INDEX, 0, MEM_CNT
    SIF DT_CELL_GETS("CC_ACTOR", IDX:INDEX, "STATE", 1) == "戦闘不能"
        CONTINUE
    SELECTCASE INDEX
        CASE IS < MAIN_TARGET_PLACEMENT
            SIF !GROUPMATCH(COLLATERAL_TARGET_TYPE, WPN_COLLATERAL_TARGET_BOTH_SIDE, WPN_COLLATERAL_TARGET_UPPER_SIDE)
                CONTINUE
            SIF MAIN_TARGET_PLACEMENT - INDEX > COLLATERAL_TARGET_RANGE
                CONTINUE
            MAP_SET CC_COLLATERAL_DAMAGE_TARGET_MAP, TOSTR(IDX:INDEX), TOSTR(MAIN_TARGET_PLACEMENT - INDEX)

        CASE IS > MAIN_TARGET_PLACEMENT
            SIF !GROUPMATCH(COLLATERAL_TARGET_TYPE, WPN_COLLATERAL_TARGET_BOTH_SIDE, WPN_COLLATERAL_TARGET_LOWER_SIDE)
                CONTINUE
            SIF INDEX - MAIN_TARGET_PLACEMENT > COLLATERAL_TARGET_RANGE
                CONTINUE
            MAP_SET CC_COLLATERAL_DAMAGE_TARGET_MAP, TOSTR(IDX:INDEX), TOSTR(INDEX - MAIN_TARGET_PLACEMENT)

        CASEELSE

    ENDSELECT
NEXT

;DEBUGPRINTFORML %MAP_TOXML(CC_COLLATERAL_DAMAGE_TARGET_MAP)%

;-------------------------------------------------
;;; 巻き添えターゲットをまとめて取得
;;; - CC_COLLATERAL_DAMAGE_TARGET_MAPから一次元配列に取得(要素数はCC_MAX_MEMBER_NUM /2でよい)
;;;   - COLLATERAL_DAMAGE_TARGET: TARGETのDID
;;;   - COLLATERAL_TARGET_RANGE: メインターゲットからの距離(絶対値) 距離減衰する攻撃とかに使う
;-------------------------------------------------
@CC_GET_COLLATERAL_DAMAGE_TARGETS(COLLATERAL_DAMAGE_TARGET, COLLATERAL_TARGET_RANGE)
#FUNCTION
#DIM MEM_CNT
#DIM REF COLLATERAL_DAMAGE_TARGET, 0
#DIM REF COLLATERAL_TARGET_RANGE, 0
#DIMS DYNAMIC TEMP_TARGET, CC_MAX_MEMBER_NUM

MEM_CNT = MAP_SIZE(CC_COLLATERAL_DAMAGE_TARGET_MAP)
MAP_GETKEYS CC_COLLATERAL_DAMAGE_TARGET_MAP, TEMP_TARGET, 1
FOR LOCAL, 0, MEM_CNT
    COLLATERAL_DAMAGE_TARGET:LOCAL = TOINT(TEMP_TARGET:LOCAL)
    COLLATERAL_TARGET_RANGE:LOCAL = TOINT(MAP_GET(CC_COLLATERAL_DAMAGE_TARGET_MAP, TEMP_TARGET:LOCAL))
    ;DEBUGPRINTFORML COLLATERAL_DAMAGE_TARGET:{LOCAL} = {COLLATERAL_DAMAGE_TARGET:LOCAL}
    ;DEBUGPRINTFORML COLLATERAL_TARGET_RANGE:{LOCAL} = {COLLATERAL_TARGET_RANGE:LOCAL}
NEXT
RETURNF MEM_CNT


code:
;-------------------------------------------------
; トークン関連
;  xml定義に移行。OBSOLETED
;-------------------------------------------------

{
  #DIMS  CONST CC_TOKEN_NAME_ENG =
    "STUN"
    ,"POISON"
    ,"BURN"
    ,"CHARM"
    ,"PANIC"
    ,"BLIND"
    ,"FRAGILE"
    ,"STRENGTH"
    ,"WEAKNESS"
    ,"GUARD"
    ,"MAG_GUARD"
    ,"PROVOKE"
    ,"DECOY"
    ,"DECOY_SHADOW"
    ,"HIDE"
    ,"MAG_BREAK"
    ,"CAST"
    ,"SONG"
    ,"CHARGE"
    ,"ADD_ATTACK"
    ,"REACT"
    ,"BARRIER"
    ,"ORGASM"
    ,"ESTRUS"
    ,"CHEST_EXPOSE"
    ,"GENITAL_EXPOSE"
    ,"MEAL_EFFECT"
}
{
  #DIMS  CONST CC_TOKEN_NAME_JP =
    "ｽﾀﾝ"
    ,"毒"
    ,"燃焼"
    ,"魅了"
    ,"混乱"
    ,"盲目"
    ,"脆弱"
    ,"強靭"
    ,"脱力"
    ,"ｶﾞｰﾄﾞ"
    ,"魔防"
    ,"挑発"
    ,"ﾃﾞｺｲ"
    ,"分身"
    ,"隠蔽"
    ,"破魔"
    ,"詠唱"
    ,"歌唱"
    ,"ﾁｬｰｼﾞ"
    ,"追撃"
    ,"再行動"
    ,"ﾊﾞﾘｱ"
    ,"❤絶頂"
    ,"❤発情"
    ,"❤乳露出"
    ,"❤秘部露出"
    ,"食事"
}
;攻撃終了のタイミングで減少するトークン
{
  #DIMS CONST CC_DECRESE_TOKEN_AFTER_ATTACK =
    "GUARD"
    ,"MAG_GUARD"
    ,"PROVOKE"
    ,"DECOY"
    ,"DECOY_SHADOW"
    ,"FRAGILE"
    ,"STRENGTH"
    ,"WEAKNESS"
    ,"ADD_ATTACK"
    ,"MEAL_EFFECT"
}

{
  #DIMS CONST CC_TOKEN_TOOLTIP_STUN = ""
    +"【スタン】
"
    +"・行動終了時に減少するトークン
"
    +"・確定で行動に失敗する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_POISON = ""
    +"【毒】
"
    +"・行動終了時に減少するトークン
"
    +"・行動時に固定ダメージを受ける
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_BURN = ""
    +"【燃焼】
"
    +"・行動終了時に減少するトークン
"
    +"・行動時に固定ダメージを受け、被ダメージが15%上昇する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_GUARD = ""
    +"【ガード】
"
    +"・行動終了時に減少するトークン
"
    +"・被ダメージが50%減少する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_FRAGILE = ""
    +"【脆弱】
"
    +"・行動終了時に減少するトークン
"
    +"・被ダメージが25%上昇する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_STRENGTH = ""
    +"【強靭】
"
    +"・行動終了時に減少するトークン
"
    +"・与ダメージが25%上昇する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_WEAKNESS = ""
    +"【脱力】
"
    +"・行動終了時に減少するトークン
"
    +"・与ダメージが25%減少する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_DECOY = ""
    +"【デコイ】
"
    +"・行動終了時に減少するトークン
"
    +"・被ダメージを無効化する
"
    +"・被ダメージ時に消滅する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_PROVOKE = ""
    +"【挑発】
"
    +"・行動終了時に減少するトークン
"
    +"・攻撃の対象に取られやすくなる
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_HIDE = ""
    +"【隠蔽】
"
    +"・行動終了時に減少するトークン
"
    +"・攻撃の対象に取られにくくなる
"
    +"・致命の一撃、致命打の与ダメージが常に上昇
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_MAG_BREAK = ""
    +"【破魔】
"
    +"・行動終了時に減少するトークン
"
    +"・魔力追加ダメージの敵魔力による減衰を50%無視
"
    +"・自身の被魔力ダメージが50%減少する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_ADD_ATTACK = ""
    +"【追撃】
"
    +"・行動終了時に減少するトークン
"
    +"・通常攻撃の回数を1加算する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_ORGASM = ""
    +"【絶頂】
"
    +"・行動終了時に減少するトークン
"
    +"・確定で行動に失敗する
"
    +"・絶頂強度に応じた被ダメージを受ける
"
}

;スタックするトークン
{
  #DIMS CONST CC_TOKEN_TOOLTIP_CAST = ""
    +"【詠唱】
"
    +"・スタックされるトークン
"
    +"・主に魔術系スキルの発動で消費される
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_SONG = ""
    +"【歌唱】
"
    +"・スタックされるトークン
"
    +"・主に歌唱系スキルの発動で消費される
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_DECOY_SHADOW = ""
    +"【分身】
"
    +"・スタックされるトークン
"
    +"・被ダメージを無効化する
"
    +"・被ダメージ時に1点消費される
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_ESTRUS = ""
    +"【発情】
"
    +"・スタックされるトークン
"
    +"・極度に発情している状態
"
    +"・性的衝動に応じた動作を引き起こす可能性がある…
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_BARRIER = ""
    +"【バリア】
"
    +"・スタックされるトークン
"
    +"・被ダメージ時にHPの代わりに消費される
"
    +"・毒・燃焼などのダメージは肩代わりされない
"
}

;その他トークン
{
  #DIMS CONST CC_TOKEN_TOOLTIP_CHEST_EXPOSE = ""
    +"【胸露出】
"
    +"・永続するトークン
"
    +"・衣服が破れ、胸が露出してる場合付与される
"
    +"・被ダメージが10%上昇する
"
}
{
  #DIMS CONST CC_TOKEN_TOOLTIP_GENITAL_EXPOSE = ""
    +"【秘部露出】
"
    +"・永続するトークン
"
    +"・衣服が破れ、局部が露出してる場合付与される
"
    +"・被ダメージが25%上昇する
"
}


code:
;-------------------------------------------------
; エネミーの行動定義
;-------------------------------------------------
@CLOSE_COMBAT_SET_ENEMY_ACTION(CHARA_DID)
#DIM  DYNAMIC CHARA_DID
#DIMS DYNAMIC ENEMY_ACTIVE_SKILL
#DIMS DYNAMIC SKILL_DEF_NAME
#DIMS DYNAMIC LIST_SKILL_ALL
#DIMS DYNAMIC LIST_SKILL
#DIMS DYNAMIC LIST_SEX_SKILL
#DIMS DYNAMIC SELECTED_SKILL
#DIMS DYNAMIC ENEMY_AI
#DIM  DYNAMIC SKILL_USE_RATE
#DIM  DYNAMIC SEX_ATTACK_USE_RATE
#DIMS DYNAMIC _XML_SKILL
#DIMS DYNAMIC AI_FUNC

; VARI CHARA_ID
; CHARA_ID = DT_CELL_GET("CC_ACTOR", CHARA_DID, "CHARA_ID", 1)
; IF CHARA_ID >= 0
;     DEBUGPRINTFORML %ANAME(CHARA_ID)%の行動決定処理
; ENDIF

;;AI_FUNCがある場合はそのAIを使用
ENEMY_AI = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_AI", 1)%
IF DIC_CONTAINSKEY(ENEMY_AI, "AI_FUNC")
    AI_FUNC = %DIC_GET(ENEMY_AI, "AI_FUNC")%
    TRYCCALLFORM CC_ENEMY_AI_%AI_FUNC%(CHARA_DID)
        RETURN
    CATCH
        DEBUGPRINTFORML "AI_FUNC"%AI_FUNC%"が見つかりませんでした"
    ENDCATCH
ENDIF

;;汎用AI
;対象エネミーが使用可能なスキルを取得
CALL CC_ENEMY_AI_GET_SKILL_LIST(CHARA_DID)
LIST_SKILL_ALL = %RESULTS:1%
LIST_SEX_SKILL = %RESULTS:2%

;スキル利用率を取得
CALL CC_ENEMY_AI_GET_SKILL_USE_RATE(CHARA_DID)
SKILL_USE_RATE = RESULT:0
SEX_ATTACK_USE_RATE = RESULT:1

;;優先行動
;スキル発動に必要なトークンが揃っている場合は優先的に使用させる
LIST_SKILL = %LIST_SKILL_ALL%
FOR LOCAL, 0, LIST_COUNT(LIST_SKILL_ALL)
    SKILL_DEF_NAME = %LIST_GET(LIST_SKILL_ALL, LOCAL)%
    CALL CC_CHECK_REQTOKEN_TOCAST(CHARA_DID, SKILL_DEF_NAME, スキル_ジャンル_戦闘)
    ;条件を満たしているなら優先的に発動
    IF RESULT == 1
        DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", SKILL_DEF_NAME, 1
        RETURN
        ;発動できない場合はリストから除外
    ELSEIF RESULT == 0
        LIST_SKILL = %LIST_REMOVEALL(LIST_SKILL, SKILL_DEF_NAME)%
    ENDIF
    ;リアクト連続使用を制約するためのフラグが立っている場合はリアクトを発動候補から除外
    IF CC_GET_ACTOR_FLAG(CHARA_DID, "REACT_USED")
        LIST_SKILL = %LIST_REMOVEALL(LIST_SKILL, "ACT_REACT")%
        ;リアクト連続使用を制約するためのフラグをリセット
        CALL CC_SET_ACTOR_FLAG(CHARA_DID, "REACT_USED", 0)
    ENDIF
NEXT

;;抽選に基づき使用スキルを決定
VARI 通常スキル使用 = 0
VARI 性的スキル使用 = 1
CALL RAND_WT_INIT
IF RAND:100 < SKILL_USE_RATE
    CALL RAND_WT_SET(通常スキル使用, SKILL_USE_RATE)
ELSEIF RAND:100 < SEX_ATTACK_USE_RATE
    CALL RAND_WT_SET(性的スキル使用, SEX_ATTACK_USE_RATE)
ENDIF

SELECTCASE RAND_WT_RESULT()
    CASE 通常スキル使用
        ;コストを必要としないスキルはランダムに発動
        CALL LIST_SHUFFLE(LIST_SKILL)
        FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
            SKILL_DEF_NAME = %LIST_GET(LIST_SKILL, LOCAL)%
            DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", SKILL_DEF_NAME, 1
            RETURN
        NEXT
    CASE 性的スキル使用
        ;セックススキルはランダムに発動
        CALL LIST_SHUFFLE(LIST_SEX_SKILL)
        FOR LOCAL, 0, LIST_COUNT(LIST_SEX_SKILL)
            SKILL_DEF_NAME = %LIST_GET(LIST_SEX_SKILL, LOCAL)%
            DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", SKILL_DEF_NAME, 1
            RETURN
        NEXT
ENDSELECT

;-------------------------------------------------
;;; エネミーが使用可能なスキルを取得し、リスト化する
;;; - RETURN
;;  RESULT    スキルが一つでもあれば1,なければ0
;;; RESULTS:0 全スキルのリスト
;;; RESULTS:1 通常アクティブスキルのリスト
;;; RESULTS:2 性的なスキルのリスト
;-------------------------------------------------
@CC_ENEMY_AI_GET_SKILL_LIST(CHARA_DID)
#DIM  CHARA_DID
#DIMS DYNAMIC ENEMY_ACTIVE_SKILL
#DIMS DYNAMIC LIST_SKILL
#DIMS DYNAMIC LIST_SEX_SKILL
#DIMS DYNAMIC LIST_SKILL_ALL
#DIMS DYNAMIC SKILL_DEF_NAME
#DIMS DYNAMIC _XML_SKILL
#DIMS DYNAMIC SKILLS, MAX_SKILLS

VARSET RESULTS
;;汎用AI
ENEMY_ACTIVE_SKILL = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_ACTIVE_SKILL", 1)%
IF ENEMY_ACTIVE_SKILL == ""
    RETURN 0
ENDIF

;対象エネミーが使用可能なスキルをリスト化
VARI SKILL_CNT
VARS SKILLS
CALL DIC_KEYS(ENEMY_ACTIVE_SKILL)
SKILL_CNT = RESULT
ARRAYCOPY "RESULTS", "SKILLS"

FOR LOCAL, 0, SKILL_CNT
    SKILL_DEF_NAME = %SKILLS:LOCAL%
    LIST_SKILL_ALL = %LIST_ADD(LIST_SKILL_ALL, SKILL_DEF_NAME)%
    XML_GET XMLID_SKILL_BATTLE, @"//defname[@parentname='%SKILL_DEF_NAME%']", _XML_SKILL, 3
    IF RESULT
        XML_GET _XML_SKILL, "//subcategory", RESULTS, 1
        IF RESULTS == "SEX"
            CALL DIC_KEYS(ENEMY_ACTIVE_SKILL)
            LIST_SEX_SKILL = %LIST_ADD(LIST_SEX_SKILL, RESULTS:LOCAL)%
        ELSE
            CALL DIC_KEYS(ENEMY_ACTIVE_SKILL)
            LIST_SKILL = %LIST_ADD(LIST_SKILL, RESULTS:LOCAL)%
        ENDIF
    ENDIF
NEXT

RESULTS:0 = %LIST_SKILL_ALL%
RESULTS:1 = %LIST_SKILL%
RESULTS:2 = %LIST_SEX_SKILL%
RETURN 1

;-------------------------------------------------
;;; スキル使用率の取得
;;; - RETURN
;;;  RESULT:0 通常スキルの使用率
;;;  RESULT:1 性的なスキルの使用率
;;; - ※通常スキル使用率が未定義の場合はデフォルト値を適用
;-------------------------------------------------
@CC_ENEMY_AI_GET_SKILL_USE_RATE(CHARA_DID)
#DIM  DYNAMIC CHARA_DID
#DIMS DYNAMIC ENEMY_AI
#DIM  DYNAMIC SKILL_USE_RATE
#DIM  DYNAMIC SEX_ATTACK_USE_RATE
#DIM  CONST DEFAULT_SKILL_USE_RATE = 25

ENEMY_AI = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_AI", 1)%
IF DIC_CONTAINSKEY(ENEMY_AI, "SKILL_USE_RATE")
    SKILL_USE_RATE = DIC_GETINT(ENEMY_AI, "SKILL_USE_RATE")
ELSE
    SKILL_USE_RATE = DEFAULT_SKILL_USE_RATE
ENDIF
IF DIC_CONTAINSKEY(ENEMY_AI, "SEX_ATTACK_USE_RATE")
    SEX_ATTACK_USE_RATE = DIC_GETINT(ENEMY_AI, "SEX_ATTACK_USE_RATE")
ENDIF

;性的な攻撃の使用確率をコンフィグ値で補正
SEX_ATTACK_USE_RATE = FTIMES(SEX_ATTACK_USE_RATE, FLCONFIG:エネミーの好色率)

RESULT:0 = SKILL_USE_RATE
RESULT:1 = SEX_ATTACK_USE_RATE
RETURN SKILL_USE_RATE

;-------------------------------------------------
;;; サキュバスなど性的な攻撃を行うエネミー向けのAI
;-------------------------------------------------
@CC_ENEMY_AI_SEXUAL_ENEMY(CHARA_DID)
#DIM  DYNAMIC CHARA_DID
#DIMS DYNAMIC ENEMY_ACTIVE_SKILL
#DIMS DYNAMIC LIST_SKILL
#DIMS DYNAMIC LIST_SEX_SKILL
#DIMS DYNAMIC SKILL_DEF_NAME
#DIM  DYNAMIC IDX, CC_MAX_MEMBER_NUM
#DIM  DYNAMIC SKILL_USE_RATE = 25 ;スキル使用確率
#DIM  DYNAMIC SEX_ATTACK_USE_RATE

;対象エネミーが使用可能なスキルを取得
CALL CC_ENEMY_AI_GET_SKILL_LIST(CHARA_DID)
LIST_SKILL = %RESULTS:1%
LIST_SEX_SKILL = %RESULTS:2%

;スキル利用率を取得
CALL CC_ENEMY_AI_GET_SKILL_USE_RATE(CHARA_DID)
SKILL_USE_RATE = RESULT:0
SEX_ATTACK_USE_RATE = RESULT:1

;;優先行動
;スキル発動に必要なトークンが揃っている場合は優先的に使用させる
FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
    SKILL_DEF_NAME = %LIST_GET(LIST_SKILL, LOCAL)%
    CALL CC_CHECK_REQTOKEN_TOCAST(CHARA_DID, SKILL_DEF_NAME, スキル_ジャンル_戦闘)
    ;条件を満たしているなら優先的に発動
    IF RESULT == 1
        DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", SKILL_DEF_NAME, 1
        RETURN
        ;発動できないならリストから除外
    ELSEIF RESULT == 0
        LIST_SKILL = %LIST_REMOVEAT(LIST_SKILL, LOCAL)%
    ENDIF
NEXT

;敵対者のキャラ情報を取得、確認し条件を見たさないスキルを候補から除外
VARI OPPONENT_SIDE
VARI MEM_CNT
VARI CHARA_ID
VARI MALE_EXIST_FLAG
VARI FEMALE_EXIST_FLAG

OPPONENT_SIDE = DT_CELL_GET("CC_ACTOR", CHARA_DID, "SIDE", 1) == 0 ? 1 # 0
MEM_CNT = DT_SELECT("CC_ACTOR", @"SIDE = {OPPONENT_SIDE}",, IDX)
FOR LOCAL, 0, MEM_CNT
    CHARA_ID = DT_CELL_GET("CC_ACTOR", IDX:LOCAL, "CHARA_ID", 1)
    IF CHARA_ID != -1
        IF IS_MALE(CHARA_ID)
            MALE_EXIST_FLAG = 1
        ELSEIF IS_FEMALE(CHARA_ID)
            FEMALE_EXIST_FLAG = 1
        ENDIF
    ENDIF
NEXT

;;発動条件を満たさないスキルを候補から除外する
;敵対者に男性がいない場合、男性を対象にした性攻撃スキルを候補から除外
IF !MALE_EXIST_FLAG
    LIST_SEX_SKILL = %LIST_REMOVEALL(LIST_SEX_SKILL, "ACT_MOLESTATION_MALE")%
ENDIF
;敵対者に女性がいない場合、女性を対象にした性攻撃スキルを候補から除外
IF !FEMALE_EXIST_FLAG
    LIST_SEX_SKILL = %LIST_REMOVEALL(LIST_SEX_SKILL, "ACT_MOLESTATION")%
ENDIF

;;抽選に基づき使用スキルを決定
VARI 通常スキル使用 = 1
VARI 性的スキル使用 = 2
CALL RAND_WT_INIT
IF RAND:100 < SKILL_USE_RATE
    CALL RAND_WT_SET(通常スキル使用, SKILL_USE_RATE)
ELSEIF RAND:100 < SEX_ATTACK_USE_RATE
    CALL RAND_WT_SET(性的スキル使用, SEX_ATTACK_USE_RATE)
ENDIF

SELECTCASE RAND_WT_RESULT()
    CASE 通常スキル使用
        ;コストを必要としないスキルはランダムに発動
        CALL LIST_SHUFFLE(LIST_SKILL)
        FOR LOCAL, 0, LIST_COUNT(LIST_SKILL)
            SKILL_DEF_NAME = %LIST_GET(LIST_SKILL, LOCAL)%
            DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", SKILL_DEF_NAME, 1
            RETURN
        NEXT
    CASE 性的スキル使用
        ;セックススキルはランダムに発動
        CALL LIST_SHUFFLE(LIST_SEX_SKILL)
        FOR LOCAL, 0, LIST_COUNT(LIST_SEX_SKILL)
            SKILL_DEF_NAME = %LIST_GET(LIST_SEX_SKILL, LOCAL)%
            DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", SKILL_DEF_NAME, 1
            RETURN
        NEXT
ENDSELECT

;-------------------------------------------------
;;; ルーチン行動用AI
;;; @CREATE_CC_ENEMY_ROUTINE_TABLEと@CC_ADD_ENEMY_ROUTINEで事前登録したルーチンに従って行動する
;-------------------------------------------------
@CC_ENEMY_AI_ROUTINE(CHARA_DID)
#DIM  CHARA_DID
#DIMS DB_NAME
#DIMS  MODE
#DIM  SEQUENCE
#DIM  CANDIDATE_NUM
#DIM  CANDIDATE, 10
#DIM  SELECTED
#DIM  WEIGHT
#DIMS ENEMY_SELECTED_SKILL

#DIM MAX_HP
#DIM HP

MODE = %DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_AI_ROUTINE_MODE", 1)%
SEQUENCE = DT_CELL_GET("CC_ACTOR", CHARA_DID, "ENEMY_AI_ROUTINE_SEQUENCE", 1)
DB_NAME '= @"CC_ENEMY_ROUTINE_TABLE_%DT_CELL_GETS("CC_ACTOR", CHARA_DID, "ENEMY_DEF_NAME", 1)%"

;条件判定に使いそうな情報を展開
MAX_HP = DT_CELL_GET("CC_ACTOR", CHARA_DID, "MAX_HP", 1)
HP = DT_CELL_GET("CC_ACTOR", CHARA_DID, "HP", 1)

;DEBUGPRINTFORML MODE = %MODE%, SEQUENCE = {SEQUENCE}
CANDIDATE_NUM = DT_SELECT(DB_NAME, @"MODE = '%MODE%' AND SEQUENCE = {SEQUENCE}",, CANDIDATE)

;シーケンスが末尾を超えているなら0に戻して再取得
IF CANDIDATE_NUM == 0
    SEQUENCE = 0
    CANDIDATE_NUM = DT_SELECT(DB_NAME, @"MODE = '%MODE%' AND SEQUENCE = {SEQUENCE}",, CANDIDATE)
ENDIF
;DEBUGPRINTFORML CANDIDATE_NUM = {CANDIDATE_NUM}
CALL RAND_WT_INIT()
FOR LOCAL, 0, CANDIDATE_NUM
    WEIGHT = DT_CELL_GET(DB_NAME, CANDIDATE:LOCAL, "WEIGHT", 1)

    ;CONDITIONに指定した条件を満たさない場合は重み0
    ;DEBUGPRINTFORML %DT_CELL_GETS(DB_NAME, CANDIDATE:LOCAL, "CONDITION", 1)% = {TOINT(STRFORM(DT_CELL_GETS(DB_NAME, CANDIDATE:LOCAL, "CONDITION", 1)))}
    SIF !TOINT(STRFORM(DT_CELL_GETS(DB_NAME, CANDIDATE:LOCAL, "CONDITION", 1)))
        WEIGHT = 0

    ;要求トークンを満たさない場合は重み0
    CALL CC_CHECK_REQTOKEN_TOCAST(CHARA_DID, DT_CELL_GETS(DB_NAME, CANDIDATE:LOCAL, "SKILL_DEF_NAME", 1), スキル_ジャンル_戦闘)
    SIF !RESULT
        WEIGHT = 0

    ;DEBUGPRINTFORML {LOCAL}: WEIGHT ={WEIGHT}
    CALL RAND_WT_SET(LOCAL, WEIGHT)
NEXT

SELECTED = RAND_WT_RESULT()
;候補なしの場合は通常攻撃
IF SELECTED == -1
    ENEMY_SELECTED_SKILL '= ""
ELSE
    ENEMY_SELECTED_SKILL = %DT_CELL_GETS(DB_NAME, CANDIDATE:SELECTED, "SKILL_DEF_NAME", 1)%
ENDIF

SIF ENEMY_SELECTED_SKILL == "NORMAL_ATTACK"
    ENEMY_SELECTED_SKILL '= ""

;DEBUGPRINTFORML ENEMY_SELECTED_SKILL %ENEMY_SELECTED_SKILL%
DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_SELECTED_SKILL", ENEMY_SELECTED_SKILL, 1

DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_AI_ROUTINE_SEQUENCE", SEQUENCE + 1, 1

;-------------------------------------------------
;;; ルーチンモード変更
;;; #### 入力パラメータ
;;; - **<必須>** CHARA_DID: アクターID
;;; - **<必須>** MODE: 変更後のモードを文字列で指定
;;; - **<任意>** SEQUENCE: 変更後の初期シーケンスを指定(非指定時0)
;-------------------------------------------------
@CC_SET_ENEMY_AI_ROUTINE_MODE(CHARA_DID, MODE, SEQUENCE = 0)
#DIM  CHARA_DID
#DIMS MODE
#DIM  SEQUENCE

DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_AI_ROUTINE_MODE", MODE, 1
DT_CELL_SET "CC_ACTOR", CHARA_DID, "ENEMY_AI_ROUTINE_SEQUENCE", SEQUENCE, 1