# 局地戦略　思考ルーチンスクリプト

## APIについて

API関数には戻り値があるものがあるが、引数が間違っているなどの致命的なエラーの場合、戻り値はなし(nil)。

## 用語定義

ユニットID：ユニットの種類を表すID。CSVファイルの左端にある数値。

地形ID：地形の種類を表すID。CSVファイルの左端にある数値。

ユニットシリアル：ユニットの実体を表すシリアルナンバー。１ゲームの間で重複はしない。

１ゲーム：ひとつのマップでの戦闘開始から戦闘決着までをいう。

イベント：イベントスクリプトによって起こされる動作。 マップ上の地形やユニット実体が変更できる。不変項目は変更できない。 イベントスクリプトは思考ルーチンスクリプトと共通のLua言語で実装される予定。 共通の関数が使えるが、思考ルーチンでイベントでやる操作はできない（エラーになる）。 思考ルーチンがルールを無視してユニットを置いたり資金を操作したりする動作は禁止ということ。

不変項目：後述する項目で☆の付くもの。スクリプトにとって不変である。 すなわち、最初のスクリプト実行時に取得したら、最後まで同じ物を利用できる。

座標：マップ座標。たいてい(x,y)で表される。 また地形などの情報はテーブルに入れられる。tbl[y*width + x]という表現があった場合、 (x,y)座標の情報はテーブル変数tblの[y*width + x]にあるという意味になる。widthはマップの横幅。

## 定義済みの定数

定数と言いつつも値を変更できてしまうが、意味がないのでやらないこと。

GUN_MAX：火器の最大数(number)。

その他、APIの説明で、半角大文字アルファベットの値が出てきたら、定義済みの定数（GROUND_CAN_LOADなど）。

## デバッグモード

### 警告オン

    ks_set_all_warning(true)

Luaが一行実行されるたびに、スクリプト状態を精査する。 一行実行されるたびに多大なループ処理を行うのであるから、実行はとても遅くなる。 配布する時はこのモードはオフにするべきである。

関数，テーブル，スレッド，ユーザーデータ，ライトユーザーデータ以外のグローバル変数を探す。 この時に英大文字でないグローバル変数があった場合、プログラマーが誤ってグローバル変数を作ってしまったものとみなして、ログに警告を出す。 Luaは一見、C言語などと同じような変数の宣言ができるように見えるが、グローバル変数を間違えて作ってしまうことはかなり多い。

## 基本定義情報の取得

### ユニット定義　☆

    local tbl = ks_get_unit_information_table()
    local unit_info = tbl[unit_id]
    local v = unit_info['value']		--[[ ユニットの値段 ]]

ユニット情報表を取得する。
tbl[unit_id]にユニット情報のテーブル unit_info が入る。
unit_info[key]にユニットの情報が入る。
とても巨大なテーブルを作成する重い処理である。

    key の種類：
    'value'：価格
    'fuelmax'：燃料
    'movemax'：移動力
    'loadmax'：最大搭載数
    'loadable：搭載可能ユニットテーブル。unit_info['loadable'][target_id]にtrue/falseが入る。
    'occupy'：占領可能フラグ。true/false
    'visibility'：視界。
    'movecost'：移動コスト。unit_info['movecost'][ground_id]にコスト値が入る。
    'guninfo'：火器テーブル。火器インデックスでアクセス。unit_info['guninfo'][gun_index]に以下の情報が入る。
    	'gunmax'：弾数
    	'minrange'：最小射程（１：直接攻撃　２以上：間接攻撃）
    	'maxrange'：最大射程
    	'radius'：半径（１：通常　２以上：メガヘクス攻撃）
    	'attack'：攻撃力テーブル（ks_get_attack_tableで得られる攻撃力表と同じ内容。unit_info['guninfo'][gun_index]['attack'][target_id]が攻撃力）

### 攻撃力定義　☆

    local tbl = ks_get_attack_table(tbl)
    local atk = tbl[attack_unit_id][0][target_unit_id]	--[[ 一番目の火器の攻撃力 ]]

攻撃力表を取得する。
tbl[attack_unit_id][gun_index][defense_unit_id] に攻撃力が入る。
火器が無い場合、nilでなく0が入る。 かなり巨大なテーブルを作成する重い処理である。

### 補給ユニット定義　☆

    local tbl_neighbor, tbl_loading = ks_get_supply_unit_table()

    if ks_bit_and(tbl_neighbor[unit_id1][unit_id2], SUPPLY_FUEL) ~= 0 then
        ..
    end

補給可能ユニット表を取得する。 tbl_xxxx[unit_id1][unit_id2] に補給可能フラグが入る。 unit_id1 が補給される側である。 テーブルに入る値はビットAND演算 ks_bit_andで使用する。

    それぞれのテーブルの意味：
    tbl_neighbor：隣接補給可能
    tbl_loading：搭載補給可能

    テーブルに入る値の意味：
    SUPPLY_FUEL：燃料補給可能
    SUPPLY_GUN ：弾薬補給可能
    SUPPLY_LIFE：ライフ補給可能
    SUPPLY_ALL ：燃料・弾薬・ライフ補給可能

### 地形とユニットの関係の定義　☆

    local tbl_ground = ks_get_ground_table()

    if ks_bit_and(tbl_ground[unit_id][ground_id], GROUND_CAN_ALL) ~= 0 then
        ..
    end

地形の上で可能な行動（搭載・降車・補給など）を取得する。 tbl_ground[unit_id][ground_id] に可能フラグが入る。 テーブルに入る値はビットAND演算 ks_bit_andで使用する。

    テーブルに入る値の意味：
    GROUND_CAN_LOAD  ：搭載可能（unit_id が輸送ユニットの時、搭載が可能）
    GROUND_CAN_UNLOAD：降車可能（unit_id が輸送ユニットの時、降車が可能）
    GROUND_CAN_RIDE  ：搭載可能（unit_id が輸送されるユニットの時、搭載が可能）
    GROUND_CAN_ALIGHT：降車可能（unit_id が輸送されるユニットの時、降車が可能）
    GROUND_CAN_ALL   ：上記全てが可能
    GROUND_CAN_CREATE：生産されることが可能
    GROUND_CAN_SUPPLY：補給されることが可能

### 移動コスト定義　☆

    local tbl = ks_get_move_cost_table()

移動コストテーブルを取得する。 tbl[unit_id][ground_id] に 移動コストが入る。

## ゲーム状態の取得

### マップサイズ　☆

    local width,height = ks_get_mapsize()

マップサイズを取得する。

### 近傍座標　☆

    local tbl_x,tbl_y = ks_get_neighbor_xy_layer(x,y,r1,r2)

(x,y)座標から半径(r1〜r2)の間のヘクス集合の座標テーブルを得る。 例えば r1=1,r2=1 ならば、(x,y)の周囲６ヘクスの座標が得られる。 r1=1 ならば(x,y)を含まない。(x,y)を含めたい場合はr1=0とする。

tbl_x[1],tbl_x[2],.. , tbl_y[1],tbl_y[2],.. に座標が入る。 マップの端では数が減る。 このAPIは１ベースインデックスの配列を返すことに注意。

### 近接判定

    local flag = ks_is_neighbor(x1,y1,x2,y2,r)

(x2,y2)座標が(x1,y1)座標から半径r以内であるかどうか判定する。 あればtrue,なければfalse

### マップ地形

    local tbl = ks_get_ground_layer()

マップ全体の地形情報を取得する。 tbl[y*width+x] に (x,y)座標の地形情報テーブルが入る。

地形はイベントで変わることもあるので、不変項目とはしていない。

    key の種類：
    'id'：地形ID
    'owner'：所属陣営。地形が施設の時だけ意味を持つ。中立施設については-1。
    'life'：ライフ。地形が施設の時だけ意味を持つ。
    'life_max'：最大ライフ。地形が施設の時だけ意味を持つ。
    'shield'：地形効果。
    'income'：収入。地形が施設の時だけ意味を持つ。
    'is_building'：施設かどうかの真偽値。
    'is_creatable'：生産を行えるかどうかの真偽値。
    'is_self_creatable'：独立生産を行えるかどうかの真偽値。
    'is_capital'：首都機能を持つかどうかの真偽値。

### マップ地形効果

    local tbl = ks_get_defense_layer()

マップ全体の地形効果を取得する。 tbl[y*width+x] に (x,y)座標の地形効果が入る。

### マップ上のユニット

    local tbl_side,tbl_serial = ks_get_unit_layer()

マップ全体のユニットシリアルを取得する。 tbl_side[y*width+x]に陣営番号が、tbl_serial[y*width+x] にユニットシリアルが入る。 ユニットが存在しない座標については nil.

### マップ移動コスト

    local tbl = ks_get_move_cost_layer(unit_id)

ユニットIDを指定し、マップ全体の移動コストを取得する。 tbl[y*width+x] に (x,y)座標の移動コストが入る。

### ゲーム状態

    local tbl = ks_get_game_information()

ゲーム状態を得る。tbl[key] に値が入る。

    key の種類：
    'sidecount'：陣営数
    'sakuteki'：索敵モードフラグ。true/false
    'turn'：経過ターン。最初のターンは零。

### 自陣営

    local my_side = ks_get_my_side()

自陣営の陣営番号を得る。

### 陣営状態

    local tbl = ks_get_side()

陣営情報を得る。tbl[side_index][key] に値が入る。

    side_index：0〜陣営数-1
    key の種類：
    'money'：資金
    'income'：収入
    'name'：名前
    'friendly':友好度テーブル。tbl['friendly'][side_index]に友好度が入る。零以下が敵。

### 全てのユニット

    local tbl = ks_get_unit_allside()

陣営全体のユニットシリアルを取得する。tbl[side_index][n] にユニットシリアルが入る。 n は 0〜陣営のユニット数-1の値とする。

ただし、索敵モード時は見えていないユニットは取得できない。

### ユニット状態

    local tbl = ks_get_unit_status(side,serial)

陣営とユニットシリアルを指定して、ユニット状態を取得する。tbl[key] に値が入る。 存在しないか、索敵モードで見えていないユニットについてはnilが返る。

key の種類：

    'side'  ：陣営番号
    'serial'：ユニットシリアル
    'id'：ユニットID
    'x'：X座標
    'y'：Y座標
    'life'：ライフ
    'fuel'：燃料
    'level'：レベル
    'experience'：経験値
    'actioned'：行動済みフラグ
    'gun' ：残弾数テーブル（火器インデックスでアクセス）
    'load'：搭載ユニットテーブル（搭載インデックスでアクセス。ユニットシリアルが入る）

### ユニット状態（場所指定）

    local tbl = ks_get_unit_status_on(x,y)

座標を指定して、ユニット状態を取得する。戻り値の内容は ks_get_unit_status と同じ。 ユニットが居ないか索敵モードで見えていない場合、戻り値はnil.

### ユニット存在

    local b = ks_get_unit_exists(x,y)

座標を指定して、ユニットが居るかどうか判定する。居るなら戻り値はtrue,居ないならfalse. 判定だけなのでks_get_unit_status_onより高速。 広範囲をいっぺんに調べるような場合、まずこれで判定してからks_get_unit_status_on()することを推奨。 また、索敵モードで見えない場合はnilが返る。

### ユニット移動距離

    local tbl = ks_get_distance_layer(x1,y1,unit_id,max_dist)

目的地への経路を探す目的の関数。

ユニットIDを指定して、(x1,y1)座標を始点とした移動可能ポイントを求める。 tbl[y*width+x] に (x1,y1)座標からの移動可能ポイントが入る。 移動可能ポイント = max_dist - 距離. すなわち始点から遠い座標ほど移動可能ポイントは小さくなる。 移動不可能な地点、及び距離が max_dist 以上の座標については要素は設定されない。 敵ユニット/味方ユニットの存在は考慮されない。

### ユニット移動範囲

    local tbl = ks_get_movable_layer(side,unit_serial)

陣営番号とユニットシリアルを指定して、現在座標を始点とした移動可能ポイントを求める（ユニットをクリックして白枠が出る範囲）。 tbl[y*width+x] に現在座標からの移動可能ポイントが入る。 移動可能ポイント = 移動力 - 距離. すなわち始点から遠い座標ほど移動可能ポイントは小さくなる。 移動不可能な地点、及び距離が max_dist 以上の座標については要素は設定されない。 敵ユニット/味方ユニットの存在は考慮される。索敵モードで影になっている所は常にユニットが居ないものとして扱われる。

### ユニット移動及び攻撃

    local damage_tbl = ks_set_attack(side,unit_serial,x1,y1,gun_index,x2,y2,exec)

指定したユニットが、(x1,y1)座標に移動して、gun_indexの火器で(x2,y2)座標を攻撃することが可能かどうかを求める。 gun_index=-1の場合、移動のみすることを意味する。 exec=true の時、可能ならば実際に操作を行う。 可能（exec=trueの時は成功）ならばテーブルが返る。不可能ならばnilが返る。 damage_tbl[y*width + x]に(x,y)座標のユニットのダメージ数値が入る。反撃を受けた場合は自身のダメージも入る。 （ダメージが零でも攻撃対象ならば数値が入る。攻撃範囲外やユニットの居ない座標についてはテーブルの要素はセットされない）。

索敵モードの時の動作には注意しなければならない。 exec=falseの時に可能とされた移動でも、exec=trueの場合は途中で衝突が起きる可能性がある。 衝突が起きた場合、攻撃は行われずまた行動終了となる。その場合の戻り値は空のテーブルである。

### ユニット移動及び降車

    tbl1 = {}
    tbl1['x'] = load_x1
    tbl1['y'] = load_y1
    tbl2 = {}
    tbl2['x'] = load_x2
    tbl2['y'] = load_y2
    load_tbl = {}
    load_tbl[0] = tbl1
    load_tbl[1] = tbl2
    local unload_tbl = ks_set_unload(side,unit_serial,x1,y1,load_tbl,exec)

指定したユニットが、(x1,y1)座標に移動して、搭載ユニットをload_tbl中に示された座標に降車することが可能かどうかを求める。 load_tbl のキーは搭載インデックス。 load_tbl の内容が空の場合、移動のみすることを意味する。 exec=true の時、可能ならば実際に操作を行う。 可能（exec=trueの時は成功）ならばテーブルが返る。不可能ならばnilが返る。 置いた場所(x,y)についてunload_tbl[y*width + x]にtrueが入る。置かなかった場所についてはテーブルの要素はセットされない。

索敵モードの時の動作には注意しなければならない。 exec=falseの時に可能とされた移動でも、exec=trueの場合は途中で衝突が起きる可能性がある。 衝突が起きた場合、降車は行われずまた行動終了となる。その場合の戻り値は空のテーブルである。

### 生産可能ユニット

    local tbl = ks_get_creatable_unit(ground_id,side)

陣営 side が地形 ground_id で現在生産可能なユニットIDのリストを求める。資金は考慮しない。 tbl[n]にユニットIDが入る。 n は 0〜生産可能なユニットの種類数-1の値とする。

### 生産可能ユニット（位置指定）

    local tbl = ks_get_creatable_unit_on(x,y,side)

陣営 side が(x,y)座標で現在生産可能なユニットIDのリストを求める。資金は考慮しない。 tbl[n]にユニットIDが入る。 n は 0〜生産可能なユニットの種類数-1の値とする。

(x,y)が陣営 side の施設ではない、(x,y)に既にユニットがある、首都の周りでしか生産可能にならない施設である という場合は、空のリストが返る。

### 生産操作

    b = ks_set_create(x,y,unit_type,exec)

(x,y)座標で指定したユニットが生産可能かどうかを求める。 exec=true の時、可能ならば実際に操作を行う。 戻り値はブーリアン型で、可能（exec=trueの時は成功）ならば true になる。

### 座標⇔インデックス相互変換

    local index = ks_index2xy(x, y)
    local x, y = ks_xy2index(index)

配列には、インデックスが y*width + x （width=マップの横幅）のものがある。 Luaには整数型が無いため、index から x,y を求めるのは面倒なので変換用の関数を用意した。

### ビット演算

    ks_bit_and(value1, value2)
    ks_bit_or(value1, value2)

value1とvalue2をビット演算した結果を返す。 Luaには整数型が無いため、ビット演算も無い。 この関数は数値型が整数の値を表している時にだけ正しく動作する。

### 変数記録

    ks_put_side_variable(key, value)

システムの変数テーブルに値を記憶させる。この値はセーブファイルに書き込まれる。 key,value は文字列として扱われる。 それ以外を値に指定した場合、key,value を文字列に変換した値が使われる。 Luaは文字列と数値の自動変換機構を持っているので問題ない （どのみちセーブファイルには文字列で記録されるので、どこかで変換のオーバヘッドがかかる。 そこで変換は Lua にまかせる方法を選んだ。 もしも入れようとする値が数値であって、文字列に変換されるとその後のパフォーマンス的に困るという場合、tostring()を使って数値の文字列表現を明示的に作ればよい）。 文字列の長さに上限はない。

### 変数取得

    ks_get_side_variable(key)

ks_put_side_variable()で記憶した値を取得する。戻り値は文字列。値が存在しない場合、戻り値は空文字列（nilでなくて）。 keyが文字列でない場合、文字列に変換される。 もしも期待する値が数値である場合、tonumber()で戻り値を数値にすればよい。

### 変数削除

    ks_remove_side_variable(key)

ks_put_side_variable()で記憶した値を削除する。値が存在しない場合でも、特にエラーにならない。 keyが文字列でない場合、文字列に変換される。

### 本体から呼び出される関数

    ks_on_side_operation()

ユニット操作および生産をするべき時に呼び出される。１フェーズにＣＯＭ１陣営につき１回。

EOF