こちらは古い情報です。
使用できる変数を増やすにある方法の方が扱いやすいので、そちらの使用を推奨します。
.csで自由に使えるローカル変数は0@~31@の32個しか存在せず、これ以上の数のオブジェクトなどを操作することは出来ません。
グローバル変数を使えば解決されますが、他のスレッドで使っていると不具合を起こします。
そこで、あらかじめスレッド内に領域を設け、そこへ直接メモリ書き込みを行うことで変数を節約します。
タイトルでは変数制限突破とありますが、変数とは扱いが違います。
また、操作も難しいものとなります。
しかし、スレッドがメモリに収まる限りいくらでも領域を大きくすることができるためとても便利です。
例:
for 0@ = 0 to 9 0093: 1@ = integer 0@ to_float 04C4: store_coords_to 5@ 6@ 7@ from_actor $PLAYER_ACTOR with_offset 0.0 1@ 0.0 0107: 2@ = create_object #KNIFECUR at 5@ 6@ 7@ gosub @get_pointer 0085: 4@ = 0@ // (int) 0012: 4@ *= 4 005A: 30@ += 4@ // (int) 0A8C: write_memory 30@ size 4 value 2@ virtual_protect 0
04C4: store_coords_to 5@ 6@ 7@ from_actor $PLAYER_ACTOR with_offset 0.0 0.0 1@ 0107: 3@ = create_object #KATANA at 5@ 6@ 7@ gosub @get_pointer 0085: 4@ = 0@ // (int) 0012: 4@ *= 4 005A: 30@ += 4@ // (int) 000A: 30@ += 40 0A8C: write_memory 30@ size 4 value 3@ virtual_protect 0 end
wait 2000
for 0@ = 0 to 9 gosub @get_pointer 0085: 4@ = 0@ // (int) 0012: 4@ *= 4 005A: 30@ += 4@ // (int) 0A8D: 2@ = read_memory 30@ size 4 virtual_protect 0 if 03CA: object 2@ exists then 0108: destroy_object 2@ end
gosub @get_pointer 0085: 4@ = 0@ // (int) 0012: 4@ *= 4 005A: 30@ += 4@ // (int) 000A: 30@ += 40 0A8D: 3@ = read_memory 30@ size 4 virtual_protect 0 if 03CA: object 3@ exists then 0108: destroy_object 3@ end end : : :get_pointer 0A9F: 30@ = current_thread_pointer 000A: 30@ += 0x10 0A8D: 30@ = read_memory 30@ size 4 virtual_protect 0 000E: 30@ -= @pool return
:pool hex //2@ - knife pool - 40byte 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//3@ - katana pool - 40byte 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 end
ナイフを前方に1m間隔で10個 刀を上方に1m間隔で10個出し、2秒後全て消すコードです。
使用変数は8個。
説明の為簡単な物を載せていますので、この場合は変数24個で作ることが出来ます。
1マス1byte
- スレッドの領域を作る。
1. 使いたい変数の数を数える。
2. 変数一つにつき0を8個hex-endで記述する
3. 使用サイズを覚えておく 変数*4が使用サイズ
4. この場合は2タイプ扱うので2タイプ目までのサイズを数える(40byte):pool hex //2@ - knife pool - 40byte 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
//3@ - katana pool - 40byte 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 end
- 最初のfor-endループの上半分
オブジェクトを作る部分は省略 gosub @get_pointer 0085: 4@ = 0@ // (int) 0012: 4@ *= 4 005A: 30@ += 4@ // (int) 0A8C: write_memory 30@ size 4 value 2@ virtual_protect 0
この部分で2@のHandleをスレッドに用意した領域に書き込みます。- 一行目
:get_pointer 0A9F: 30@ = current_thread_pointer 000A: 30@ += 0x10 0A8D: 30@ = read_memory 30@ size 4 virtual_protect 0 000E: 30@ -= @pool return
このスレッドのポインタを取得し、スレッド構造体+0x10 = スクリプトの先頭アドレスへポインタを移動させます。
ラベルはスクリプトの先頭からのオフセットの符号を反転させたものなので先頭アドレスからラベルを引きます。
最終的に30@は:poolのポインタとなります。 - 二行目
for-endで使用するカウンターを利用します。 - 三、四行目
カウンター*4 4byteずつ使用するので、4byteポインタを進めます - 五行目
ポインタ30@に2@(Handle)を書き込みます。
変数は型を問わずすべて4byteのサイズを持っているので、sizeは4を指定します。
- 一行目
- 最初のfor-endループの下半分
形は上のとほぼ同じです。違いは000A: 30@ += 40
が追加されただけです。
同じ計算式でならば当然同じ場所に書き込まれ、2@が書き込まれた分が消えてしまいます。
ですので、そこから2タイプ目までのサイズを足します。
このループを抜けると、設定した領域に値が書き込まれた状態になります。
二番目のfor-endのループで一番目で書き込んだ値を読み込みます。
読み込んだ値がそのままオブジェクトのHandleなので、いつものようにオブジェクトを操作することが出来ます。