素晴らしいかもしれないメモ書き

Last-modified: 2015-05-03 (日) 21:30:02
CVehicle+0x94C
  CVehicle+0x950
  戦車、消防車などの主砲の向き。
  上がヘディング、下がピッチ。
  FLOAT、単位はラジアン。
  ########################
  チチチ音
  018C: play_sound 1190 at 0.0 0.0 0.0
  ########################
  Player.SetClothes($PLAYER_CHAR, "Alex_blade_d", "AlexBlade", 0)
  Player.Build($PLAYER_CHAR)
  着替えです。モデルをLoadしておく必要はありません。
  (プレイヤーのハンドル, テクスチャ, モデル, 部位ID)の順に書きます。
  服をIDEに追加する必要が無い上、しゃがみやジャンプ中でも実行できて便利です。
  いつも撮影前に使ってます。
  07C0: load_path 856
  while 87C1: not path 856 available
  wait 0
  end
  05EB: assign_car 5@ to_path 856
  06FD: set_car 5@ speed_on_path_to 0.95
  CarPath基本形。
  あの自転車ビル登りのタネはこれです。
  友達をSAMPに集めるか、もしくはデフォのAIを上手に使えば、映画のようなカーチェイスも作れるはずです。
  他にもPath関係のコードはあるので、"Car Path"で検索するといいです。
  0A8D: 10@ = read_memory 0xB6F9CC size 4 virtual_protect 0
  0A8D: 11@ = read_memory 0xB6F9D0 size 4 virtual_protect 0
  0A8D: 12@ = read_memory 0xB6F9D4 size 4 virtual_protect 0
  0A8D: 20@ = read_memory 0xB6F9AC size 4 virtual_protect 0
  0A8D: 21@ = read_memory 0xB6F9B0 size 4 virtual_protect 0
  0A8D: 22@ = read_memory 0xB6F9B4 size 4 virtual_protect 0
  カメラ座標、カメラ先座標を求めます。
  068D、068Eと違って、CamHackの座標も求められます。
  FOVは分かりませんでしたとさ。
  0A97: 2@ = car 19@ struct
  000A: 2@ += 68
  0A8C: write_memory 2@ size 4 value 0.0 virtual_protect 0
  000A: 2@ += 4
  0A8C: write_memory 2@ size 4 value 0.0 virtual_protect 0
  000A: 2@ += 4
  0A8C: write_memory 2@ size 4 value 0.0 virtual_protect 0
  07D5: set_car 19@ velocity_in_direction_XYZ 4@ 5@ 6@ rotation_velocitiesXY 0.0 0.0 unk 0.0
  毎フレーム07D5を実行するようなコードを書いた人はいるんじゃないでしょうか。
  信じられない速さで飛んでゆくのは、このコードが速度を上書きするのではなく、”加算”するからです。
  思ったとおりの速さにするには、メモリーから速度を0にしてやらねばなりません。
  009A: 2@ = create_actor_pedtype 23 model #NULL at 7@ 8@ 9@
  02AB: set_actor 2@ immunities BP 1 FP 1 EP 1 CP 1 MP 1
  02E2: set_actor 2@ weapon_accuracy_to 100
  0337: toggle_actor 2@ visibility 0
  0489: toggle_actor 2@ muted 1
  0619: toggle_actor 2@ collision_detection 0
  081A: set_actor 2@ weapon_skill_to 1
  04D8: toggle_actor 2@ drowns_in_water 0
  0350: set_actor 2@ maintain_position_when_attacked 1
  060A: create_decision_maker_type 0 store_to 32@ // decision\allowed\m_.ped files
  060B: set_actor 2@ decision_maker_to 32@
  「動じない人」です。
  動画では、にとりの装甲車の上にこいつがTurretされてました。
  特に最後の2行は重要で、これで近くで車が燃えても無視してくれます。
  0A96: 30@ = actor $PLAYER_ACTOR struct
  0A96: 31@ = actor 9@ struct
  30@ += 0x14
  31@ += 0x14
  0A8D: 30@ = read_memory 30@ size 4 virtual_protect 0
  0A8D: 31@ = read_memory 31@ size 4 virtual_protect 0
  for 0@ = 0 to 11
  0A8D: 20@ = read_memory 31@ size 4 virtual_protect 0
  0A8C: write_memory 30@ size 4 value 20@ virtual_protect 0
  30@ += 0x4
  31@ += 0x4
  end
  Actor:9@の回転Matrixをプレイヤーにも適用してやります。
  座標、角度計算が面倒なときに使います。
  ムーンウォークしたり、ビルだって垂直に駆け上がれるはずです。
  0619: enable_actor $PLAYER_ACTOR collision_detection 0
  04C4等
  0A96: 30@ = actor $PLAYER_ACTOR struct
  30@ += 0x14
  0A8D: 30@ = read_memory 30@ size 4 virtual_protect 0
  30@ += 0x30
  0A8C: write_memory 30@ size 4 value 7@ virtual_protect 0
  30@ += 0x4
  0A8C: write_memory 30@ size 4 value 8@ virtual_protect 0
  30@ += 0x4
  0A8C: write_memory 30@ size 4 value 9@ virtual_protect 0
  当たり判定の無いアクターの動かし方です。
  083Cはとんでもない速度制限がありますが、こっちで回避できます。
  また、3行目以降のメモリ操作はアクターの座標を操作してるものですが、
  アニメーションを保持したまま座標操作が出来ます。
  また、”指定した座標より少し上に出現する”という現象が起きません。
  06BD: no_obstacles_between 18@ 19@ 20@ and 15@ 16@ 17@ solid 1 car 1 actor 1 object 1 particle 0
  0339: anything_in_cube_cornerA 15@ 16@ 17@ cornerB 15@ 16@ 17@ solid 0 car 1 actor 0 object 0 particle 0
  ~間に何かあるか?を調べるこーど。
  06BDは超頻出コードです。06BDが”辺”なのに対して、0339は”直方体”です。
  0339のほうが大雑把に計算します。
  色んな動画で使用。
  if
  Actor.Animation($PLAYER_ACTOR) == "Sprint_civi"
  then
  0393: actor $PLAYER_ACTOR perform_animation "Sprint_civi" at 25.0 times_normal_rate
  end
  アニメーションの速度がいぢれる。
  走るアニメーションだと、走る速度も上がります。
  色んな動画で使用。
  08C6: set_actor $PLAYER_ACTOR stay_on_bike 1
  全速力のAlexさんと正面衝突しても、バイクから落ちなくなります。
  水中も例外では無いです。
  藤原もっこりで使用。
  まずは訂正から。
  前の記事のカメラ座標を求めるこーどですが、
  カメラ先座標の方はローカル座標が出てきてしまいます。
  その続きに
  0013: 20@ *= 100.0
  0013: 21@ *= 100.0
  0013: 22@ *= 100.0
  005B: 20@ += 10@ // (float)
  005B: 21@ += 11@ // (float)
  005B: 22@ += 12@ // (float)
  …と書けば、20-22@にワールド座標が入ります。
  100.0をかけてるのは後で調整しやすいようにするためだったり。
  092F: lock_camera_target_point 0
  0930: lock_camera_position 0
  0931: lock_camera_zoom 0
  0936: set_camera 0.0 0.0 0.0 position_to 10.0 10.0 10.0 time 15000 drop_mode 1
  0920: point_camera 10.0 10.0 10.0 transverse_to 20.0 20.0 20.0 time 15000 mode 1
  0922: set_camera_zoom_in_factor 55.0 out_factor 85.0 timelimit 6000 mode 1
  092F: lock_camera_target_point 1
  0930: lock_camera_position 1
  0931: lock_camera_zoom 1
  Camera基本形。
  timeをずらしたり、中継点を設けたりすると、良いカメラワークが生まれることも。
  戻すときは
  0925: restore_camera_to_user_defined
  Camera.Restore_WithJumpCut
  で。
  必要に応じて
  0373: set_camera_directly_behind_player
   or
  03C8: set_camera_directly_before_player
  も。
  067C: put_camera_on_actor 0@ with_offset -0.7 -1.0 0.7 rotation 0.0 2.0 0.0 0.0 2
  0679: put_camera_on_car 5@ with_offset -3.0 6.0 0.0 rotation 0.3 0.0 1.0 0.0 2
  カメラを人or車に設置。そのカメラは設置した本人を向きます。
  067B: put_camera_on_car 0@ with_offset 0.0 0.0 0.0 point_to_actor 1@ tilt 0.0 2
  067E: put_camera_on_actor 0@ with_offset 0.0 0.0 0.0 point_to_actor 1@ 0.0 mode 2
  ↑のと似てますが、設置した人とは別の人を向きます。
  また、何も無い定点を見るということは出来ないようなので、
  そんなときは透明なダミーの人を使うことになるでしょう。
  0003: shake_camera 100
  099C: jiggle_camera type 1 timelimit 20000.0 intensity 3.0
  052C: set_player $PLAYER_CHAR drunk_visuals 100
  カメラが揺れる系
  0003は爆発の時の揺れみたいな感じ。
  099Cはもう少しグニャグニャと揺れます。typeの値を変えれば揺れ方も変わるようです。
  052Cはトゥルースの農場焼きで使われてます。酒か薬で酔った感じに揺れます。
  02A3: enable_widescreen 1
  0A48: enable_menu_access_in_widescreen_mode 1
  ワイドスクリーンです。ちょっと映画っぽくなります。
  0A48を使うと、途中でメニューを出すことが出来るようになります。
  015D: set_gamespeed 1.0
  そのまんま。ゲームの速度です。
  ゼロにしても止まるわけじゃあないです。
  0615: define_AS_pack_begin 90@
  05D3: AS_actor -1 goto_point 219.1689 119.2266 1003.2188 mode 4 30000 ms // versionA
  0639: AS_actor -1 rotate_to_actor $PLAYER_ACTOR
  0616: define_AS_pack_end 90@
  0618: assign_actor $ACTOR_REMILIA to_AS_pack 90@
  0615と0616の間に挟まれたアクションを、上から順番に実行していくコードです。
  変数操作などのコードは無視されます。実行されるコードには決まりがあるようですが、「AS_actor」が含まれるやつは必ず実行されると考えてもいいです。
  ”-1”というのは、後で0618で設定される動作主です。
  0615と0616はスレッドを跨いで働くこともあります。詳しくはmain.scm参照。
  0792: disembark_instantly_actor $PLAYER_ACTOR
  0687: clear_actor $PLAYER_ACTOR task
  何かのアクションをしてる時にアニメーションをさせようとしても無視されます。
  直前に、このどちらか、あるいは両方を使います。(なげやり
  04ED: load_animation "POWER"
  while 04EE: animation "POWER" loaded
  wait 0
  end
  0812: AS_actor $ACTOR_ALEX perform_animation "ham_air_a" IFP_file "POWER" 1000.0 loopA 1 lockX 0 lockY 0 lockF 0 time -1 // versionB
  アニメーション基本形。
  versionA、versionCもあるみたいですが、基本的にはこっちを使います。多分。
  loopAの前の数値は早さでしょうか。数値が低いとゆっくりとアニメーションに移りますが、逆に高いと即座にアニメーションに移ります。
  loopAはループするか否か、lockXlockYはよく分からないので例を挙げます。
  X0Y0だと、アニメーション後に元居た座標に戻ってきます。
  X1Y1だと、アニメーション終了時の座標に残ります。(人に当たり判定が無いと動かない。)
  X1Y0だと、……<うp主の表現力を恨んでください。>
  lockFを1にすると、アニメーションが終わったときにその体制のまま固まります。
  timeはアニメーションする時間です。一回きりで終了させるときは-1と書きます。
  0611: actor $ACTOR_ALEX performing_animation "ham_air_a"
  0613: 1@ = actor $PLAYER_ACTOR animation 40@v time
  0611はif文で使うやつ。
  0613でアニメーションの進度(0.0~1.0)が求められ、条件分岐などに使われるような気がする。
  0A92: create_custom_thread "Homurang_StruR.s"
  かすたむ☆すれっど
  一つのcsで並列処理が不可能なとき、面倒なときに使います。
  もっこり3夜で乱用してました。
  DriveByRPGでも使ってるので、詳しい使い方はそっちをみるといいかも。
  #####################################################################
  csでvtol機のスラスターを下に向けるにはどうすればいいでしょうか
  0A97: 0@ = car 0@ struct
  000A: 0@ += 0x86C
  0A8C: write_memory 0@ size 2 value 5000 virtual_protect 0
  #####################################################################
  速度をもった銃弾の作成
  0AA5: call 0x736010 num_params 8 pop 8 [速度Z] [速度Y] [速度X] [位置Z] [位置Y] [位置X] [武器ID] [射手(NULL, *CPed, *CVehicle)]
  missile.csのミサイルの作成
  0AAA: 30@ = thread 'MISSILE' pointer
  if
  8039: not 30@ == 0
  then
  000A: 30@ += 0xB0
  0A8D: 31@ = read_memory 30@ size 4 virtual_protect 0
  0012: 31@ *= 0x0A
  000E: 30@ -= 0x6C
  0A8D: 30@ = read_memory 30@ size 4 virtual_protect 0
  005A: 30@ += 31@ // (int)
  000A: 30@ += 0x0F
  0012: 30@ *= 0x04
  0AAA: 31@ = thread 'MISSILE' pointer
  005A: 30@ += 31@ // (int)
  0A8C: write_memory 30@ size 4 value [射手(NULL, *CPed, *CVehicle)] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value 0 virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [種類] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value 0 virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [目標(NULL, *CPed, *CVehicle)] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [位置X] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [位置Y] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [位置Z] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [回転H] virtual_protect 0
  000A: 30@ += 0x04
  0A8C: write_memory 30@ size 4 value [回転P] virtual_protect 0
  0AAA: 30@ = thread 'MISSILE' pointer
  000A: 30@ += 0xB0
  0A8D: 31@ = read_memory 30@ size 4 virtual_protect 0
  000A: 31@ += 0x01
  if
  0039: 31@ == 0x40
  then
  0006: 31@ = 0x00
  end
  0A8C: write_memory 30@ size 4 value 31@ virtual_protect 0
  end
  mininuke.csの核爆発の作成
  0AAA: 14@ = thread 'MININUKE' pointer
  if
  8039: not 14@ == 0
  then
  000A: 14@ += 0x3C
  0A8C: write_memory 14@ size 4 value 1 virtual_protect 0
  000A: 14@ += 0x4
  0A8C: write_memory 14@ size 4 value [位置X] virtual_protect 0
  000A: 14@ += 0x4
  0A8C: write_memory 14@ size 4 value [位置Y] virtual_protect 0
  000A: 14@ += 0x4
  0A8C: write_memory 14@ size 4 value [位置Z] virtual_protect 0
  end
  #####################################################################
  記事#478の
  005A: 2@ += 1@ // (int)
  の処理が終わった時点で2@にはボーンの姿勢を表す行列へのポインタが
  入っているのでそれを使って、
  :BONETEST
  wait 0
  if
  056D: actor $PLAYER_ACTOR defined
  jf @BONETEST
  0AB1: call_scm_func @GET_BONE_OFFSET 5 actor $PLAYER_ACTOR bone 6 offset 0.0 0.0 0.0 store_to 0@ 1@ 2@
  04D5: create_corona_at 0@ 1@ 2@ radius 0.05 type 0 flare 0 RGB 255 255 255
  0AB1: call_scm_func @GET_BONE_OFFSET 5 actor $PLAYER_ACTOR bone 6 offset 0.1 0.0 0.0 store_to 0@ 1@ 2@
  04D5: create_corona_at 0@ 1@ 2@ radius 0.05 type 0 flare 0 RGB 255 0 0
  0AB1: call_scm_func @GET_BONE_OFFSET 5 actor $PLAYER_ACTOR bone 6 offset 0.0 0.1 0.0 store_to 0@ 1@ 2@
  04D5: create_corona_at 0@ 1@ 2@ radius 0.05 type 0 flare 0 RGB 0 255 0
  0AB1: call_scm_func @GET_BONE_OFFSET 5 actor $PLAYER_ACTOR bone 6 offset 0.0 0.0 0.1 store_to 0@ 1@ 2@
  04D5: create_corona_at 0@ 1@ 2@ radius 0.05 type 0 flare 0 RGB 0 0 255
  0A9F: 0@ = current_thread_pointer
  000A: 0@ += 0x40
  0AB1: call_scm_func @GET_BONE_OFFSET 5 actor $PLAYER_ACTOR bone 6 offset 0.8 -0.03 0.03 store_to 1@ 2@ 3@
  0A9F: 4@ = current_thread_pointer
  000A: 4@ += 0x50
  0AB1: call_scm_func @GET_BONE_OFFSET 5 actor $PLAYER_ACTOR bone 6 offset 80.0 -3.0 3.0 store_to 5@ 6@ 7@
  0A9F: 20@ = current_thread_pointer
  000A: 20@ += 0x5C
  0A9F: 21@ = current_thread_pointer
  000A: 21@ += 0x88
  0AA7: call_function 0x56BA00 num_params 12 pop 12 1 0 0 1 1 1 1 1 21@ 20@ 4@ 0@ 18@
  if
  8039: not 18@ == 0
  jf @BONETEST
  005B: 12@ += 8@ // (float)
  005B: 13@ += 9@ // (float)
  005B: 14@ += 10@ // (float)
  04D5: create_corona_at 8@ 9@ 10@ radius 0.1 type 0 flare 0 RGB 255 0 255
  04D5: create_corona_at 12@ 13@ 14@ radius 0.1 type 0 flare 0 RGB 0 255 0
  jump @BONETEST
  :GET_BONE_OFFSET
  0A96: 0@ = actor 0@ struct
  0085: 5@ = 0@ // (int)
  000A: 5@ += 0x18
  0A8D: 5@ = read_memory 5@ size 4 virtual_protect 0
  0AA7: call_function 0x734A40 num_params 1 pop 1 5@ 5@ // _clumpGetFirstSkinAtomicHAnimHierarchy
  0012: 1@ *= 0x4
  000A: 1@ += 0x488
  005A: 1@ += 0@ // (int)
  0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0
  000A: 1@ += 0x14
  0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0
  0AA7: call_function 0x7C51E0 num_params 2 pop 2 1@ 5@ 1@ // _RpHAnimIDGetIndex
  0AA7: call_function 0x7C5160 num_params 1 pop 1 5@ 5@ // _RpHAnimHierarchyGetMatrixArray
  0012: 1@ *= 0x40
  005A: 1@ += 5@ // (int)
  0A9F: 5@ = current_thread_pointer
  000A: 5@ += 0x44
  0AA5: call 0x54EEF0 num_params 4 pop 4 5@ 1@ 1 5@ // _transofrmPoints
  0AB2: ret 3 2@ 3@ 4@
  GET_BONE_OFFSETがその関数です。
  敵がグレネードランチャー使ってくるスクリプトは作りませんが、一言。
  0209: 12@ = random_int_in_ranges 0 100
  ではフレームレートが高いほどグレネードランチャーを使ってくる確率が高くなります。
  32@ > 5000 があるので違いはほとんど分からないかもしれませんが、
  32@ > 5000 をとってやると確率はフレームレートに比例するようになります。
  最大を100ではなく、前フレームからの経過時間の数倍にすると常に同じ確率になります。
  #####################################################################
  スクリプトでの保護(?)のようなもののフラグが分かりました。多分。
  構造体の種類によってオフセットが違います。全部1バイト。
  CPed+0x484
  0x01 その辺の人
  0x02 スクリプトで使われてる人
  CVehicle+0x4A4
  0x01 その辺の車
  0x02 スクリプトで使われている車
  CObject+0x13C
  0x01 マップオブジェクト
  0x02 スクリプトで使われている物
  0x03 その辺の物
  0x05 拾える物、他
  この値を目安に削除するとか放っておくとか決めるといいでしょう。
  #####################################################################
  例えば、オブジェクトを飛ばして衝突したら爆発するスクリプトを作ろうとしたら、
  オブジェクトを作成し飛ばした後、
  for ....
  if
  04DA: (check) has_object 0@ collided
  then
  ..
  ..
  ..
  end
  end
  などとループ処理を使って管理していました。
  しかし.sファイルを使えば、
  0@ 1@ 2@ に発射速度やオブジェクトの作成座標を格納しておき、
  0A92: create_custom_thread "~.s" 0@ 1@ 2@
  でスレッドを作成、あとは.s側でオブジェクトの処理を
  単独で行わせればいいのです。
  #####################################################################
  0A8D: 10@ = read_memory 0xB6F9CC size 4 virtual_protect 0
  0A8D: 11@ = read_memory 0xB6F9D0 size 4 virtual_protect 0
  0A8D: 12@ = read_memory 0xB6F9D4 size 4 virtual_protect 0
  0A8D: 20@ = read_memory 0xB6F9AC size 4 virtual_protect 0
  0A8D: 21@ = read_memory 0xB6F9B0 size 4 virtual_protect 0
  0A8D: 22@ = read_memory 0xB6F9B4 size 4 virtual_protect 0
  カメラ座標、カメラ先座標を求めます。
  068D、068Eと違って、CamHackの座標も求められます。
  #####################################################################
  0922: set_camera_zoom_in_factor 50.0 out_factor 50.0 timelimit 100 mode 1
  The vital activity was stopped, and it died.
  #####################################################################
  火炎瓶の炎は(実行時アドレスで)0x5E5F7Eと0x5E8D0Bの
  jnz(0F85)をnop+jmp(90E9)に書き換えてやると消えます。
  0x5E5F7E 0x90
  0x5E5F7F 0xE9
  0x5E8D0B 0x90
  0x5E8D0C 0xE9
  投げられた火炎瓶の赤い軌跡は0x536633に同じことをすると消えます。
  0x536633 0x90
  0x536634 0xE9
  BYTE[]ではなくWORDで置き換えるときはエンディアンに注意してください。
  Intel系の実行コードはリトルエンディアンになっています。
  #####################################################################
  これはまた残酷ですね。
  0xBA86F0からMarkerの構造体が始まり、一つのサイズは0x28バイト、要素数は0xB0。
  +0x04 DWORD アタッチ先ハンドル
  +0x14 WORD マーカーの色
  +0x26 BYTE アタッチ先の種類(車04 人08 物0C)
  これだけあれば十分でしょう。
  06BCについては知りません。
  :resetactor
  for 3@ = 0xBA86F0 to 0xBAA248 step 0x28
      000A: 3@ += 0x14
      0A8D: 4@ = read_memory 3@ size 2 virtual_protect 0
      000E: 3@ -= 0x14
      0012: 4@ *= 0x10000
      0085: 5@ = 3@ // (int)
      000E: 5@ -= 0xBA86F0
      0016: 5@ /= 0x28
      005A: 4@ += 5@ // (int) //mark handle
      000A: 3@ += 0x26
      0A8D: 5@ = read_memory 3@ size 1 virtual_protect 0 //handle kind
      000E: 3@ -= 0x26
      if and //0100=car 1000=actor 1100=object
      88B7: not test 5@ bit 2
      08B7: test 5@ bit 3
      then
          000A: 3@ += 0x04
          0A8D: 5@ = read_memory 3@ size 4 virtual_protect 0 //actor handle
          000E: 3@ -= 0x04
          if
          003B: (check) 5@ == 26@ // (int)
          then
              0164: disable_marker 4@
          end
      end
  end
  return
  #####################################################################
  ボーンの位置を求める
  2009年05月14日 (木) 13:09 | 編集
  タイトルの通りです。
  008B: 1@ = $PlAYER_ACTOR // (int)
  0006: 2@ = 6
  gosub @GETBONE
  04D5: create_corona_at 0@ 1@ 2@ radius 0.1 type 0 flare 0 RGB 0 255 0
  :GETBONE
  0A96: 0@ = actor 1@ struct
  0085: 1@ = 0@ // (int)
  000A: 1@ += 0x18
  0A8D: 1@ = read_memory 1@ size 4 virtual_protect 0
  0AA7: call_function 0x734A40 num_params 1 pop 1 1@ 1@ // _clumpGetFirstSkinAtomicHAnimHierarchy
  0012: 2@ *= 0x4
  000A: 2@ += 0x488
  005A: 2@ += 0@ // (int)
  0A8D: 2@ = read_memory 2@ size 4 virtual_protect 0
  000A: 2@ += 0x14
  0A8D: 2@ = read_memory 2@ size 4 virtual_protect 0
  0AA7: call_function 0x7C51E0 num_params 2 pop 2 2@ 1@ 2@ // _RpHAnimIDGetIndex
  0AA7: call_function 0x7C5160 num_params 1 pop 1 1@ 1@ // _RpHAnimHierarchyGetMatrixArray
  0012: 2@ *= 0x40
  005A: 2@ += 1@ // (int)
  000A: 2@ += 0x30
  0A8D: 0@ = read_memory 2@ size 4 virtual_protect 0
  000A: 2@ += 0x4
  0A8D: 1@ = read_memory 2@ size 4 virtual_protect 0
  000A: 2@ += 0x4
  0A8D: 2@ = read_memory 2@ size 4 virtual_protect 0
  return
   {
  1 Spine1
  2 Head
  3 R UpperArm
  4 L UpperArm
  5 R Hand
  6 L Hand
  7 R Thigh
  8 L Thigh
  9 R Foot
  10 L Foot
  11 L Calf
  12 R Calf
  13 R ForeArm
  14 L ForeArm
  15 Bip01 R Clavicle
  16 Bip01 L Clavicle
  17 Neck
  18 Jaw
   }
  1@に人のハンドル、2@に070Aで使うボーン番号を格納して呼び出すと
  座標が0@ 1@ 2@に格納されて帰ってきます。
  15行目の処理後には2@にD3DXMATRIXへのポインタが格納されているので、
  ベクトルを変換してかけたりすればボーンからの相対座標も変換できます。
  また、6-11行目の処理を省けば2@にボーンIDを直接渡すことも可能です。
  実行ファイルによっては0x7C51E0が0x7C51A0に、
  0x7C5160が0x7C5120になっていることもあるようです。
  関数の先頭アドレスの値を調べることで判別できそうです。
  #####################################################################
  新機能他
  2009年06月06日 (土) 16:21
  ミサイルスクリプトの解説でも。
  とりあえずやっていることといえば
  バッファオーバーランと0埋めによる変数拡張
  fgetsとsscanfによるテキスト形式の設定の読みこみ
  機械語の埋め込みと実行
  低級フック
  --------------------------------------------------------------------------------
  バッファオーバーランと0埋めによる変数拡張
  バッファオーバーランを使ったアクセスはCLEO以前にSCM Opcodeだけで
  メモリの値を読み書きするのに使われていましたが、CLEOの拡張コードは
  バイト毎、仮想保護の操作も可能なためほとんど使われない存在となっていました。
  この拡張コードはメモリの読み書きには適していますが、変数の拡張には適していません。
  たとえば、スクリプトのコード内に0などで埋めたバッファを置いておき、
  それを拡張変数として使用し、この拡張変数の値を1増やすとします。
  まずは拡張コードを使用した場合。
  0A9F: 0@ = current_thread_pointer
  000A: 0@ += 0x10
  0A8D: 0@ = read_memory 0@ size 4 virtual_protect 0
  000E: 0@ -= @EXT_VAR
       :
  0A8D: 1@ = read_memory 0@ size 4 virtual_protect 0
  000A: 1@ += 1
  0A8C: write_memory 0@ size 4 value 1@ virtual_protect 0
       :
  :EXT_VAR
  hex
  00000000
  end
  バッファオーバーランを使用した場合。
  0A9F: 32@ = current_thread_pointer
  000A: 1@ += 0x10
  0A8D: 0@ = read_memory 1@ size 4 virtual_protect 0
  000A: 0@ += 4
  000A: 1@ += 0x2C
  000E: 0@ -= @EXT_VAR
  0062: 0@ -= 1@ // (int)
  0016: 0@ /= 4
       :
  000A: 0@(0@,1i) += 1
       :
  :EXT_VAR
  hex
  00000000 // padding
  00000000
  00000000 // padding
  end
  前者では初期化時のコードとバッファが最小で済みますが、
  値を変更する場合にはメモリの読み書きが伴い、さらに0@に加えて1@を使用します。
  一方後者では初期化時のコードが長くなり、バッファの前後にコードのズレを考慮した詰め物を
  置いておかないといけませんが、値を変更する場合は0@だけでアクセス可能です。
  これは多数の変数を使用するコードではより顕著になります。
  0A9F: 0@ = current_thread_pointer
  000A: 0@ += 0x10
  0A8D: 0@ = read_memory 0@ size 4 virtual_protect 0
  000E: 0@ -= @EXT_VAR
       :
  0A8D: 1@ = read_memory 0@ size 4 virtual_protect 0
  000A: 0@ += 0x4
  0A8D: 2@ = read_memory 0@ size 4 virtual_protect 0
  000A: 0@ += 0x4
  0A8D: 3@ = read_memory 0@ size 4 virtual_protect 0
  000A: 0@ += 0x4
  0A8D: 4@ = read_memory 0@ size 4 virtual_protect 0
  000A: 0@ += 0x4
  0A8D: 5@ = read_memory 0@ size 4 virtual_protect 0
  000A: 0@ += 0x4
  0A8D: 6@ = read_memory 0@ size 4 virtual_protect 0
  000A: 0@ += 0x4
  0A8D: 7@ = read_memory 0@ size 4 virtual_protect 0
  0400: store_coords_to 5@ 6@ 7@ from_object 1@ with_offset 2@ 3@ 4@
  0A8C: write_memory 0@ size 4 value 7@ virtual_protect 0
  000E: 0@ -= 0x4
  0A8C: write_memory 0@ size 4 value 6@ virtual_protect 0
  000E: 0@ -= 0x4
  0A8C: write_memory 0@ size 4 value 5@ virtual_protect 0
  000E: 0@ -= 0x4
  0A8C: write_memory 0@ size 4 value 4@ virtual_protect 0
  000E: 0@ -= 0x4
  0A8C: write_memory 0@ size 4 value 3@ virtual_protect 0
  000E: 0@ -= 0x4
  0A8C: write_memory 0@ size 4 value 2@ virtual_protect 0
  000E: 0@ -= 0x4
  0A8C: write_memory 0@ size 4 value 1@ virtual_protect 0
       :
  :EXT_VAR
  hex
  00000000
  00000000
  00000000
  00000000
  00000000
  00000000
  00000000
  end
  0A9F: 32@ = current_thread_pointer
  000A: 1@ += 0x10
  0A8D: 0@ = read_memory 1@ size 4 virtual_protect 0
  000A: 0@ += 4
  000A: 1@ += 0x2C
  000E: 0@ -= @EXT_VAR
  0062: 0@ -= 1@ // (int)
  0016: 0@ /= 4
       :
  0400: store_coords_to 4@(0@,1i) 5@(0@,1i) 6@(0@,1i) from_object 0@(0@,1i) with_offset 1@(0@,1i) 2@(0@,1i) 3@(0@,1i)
       :
  :EXT_VAR
  hex
  00000000 // padding
  00000000
  00000000
  00000000
  00000000
  00000000
  00000000
  00000000
  00000000 // padding
  end
  --------------------------------------------------------------------------------
  fgetsとsscanfによるテキスト形式の設定の読みこみ
  0x536F80はfgets(BUFFER, BUFFER_MAX, fp)
  3@(3@,1i)は:FUNC_03のアドレスです。
  viod FUNC_03(void* pDest, const char* sFormat, const char* sBuffer)
  {
  sscanf(sBuffer, sFormat, pDest + 0x00, pDest + 0x04, pDest + 0x08, pDest + 0x0C, pDest + 0x10, pDest + 0x14, pDest + 0x18, pDest + 0x1C, pDest + 0x20, pDest + 0x24, pDest + 0x28, pDest + 0x2C, pDest + 0x30, pDest + 0x34, pDest + 0x38, pDest + 0x3C, pDest + 0x40, pDest + 0x44, pDest + 0x48, pDest + 0x4C, pDest + 0x50, pDest + 0x54, pDest + 0x58, pDest + 0x5C, pDest + 0x60, pDest + 0x64, pDest + 0x68, pDest + 0x6C, pDest + 0x70, pDest + 0x74, pDest + 0x78, pDest + 0x7C, pDest + 0x80, pDest + 0x84, pDest + 0x88, pDest + 0x8C, pDest + 0x90, pDest + 0x94, pDest + 0x98, pDest + 0x9C);
  }
  コードは以下のようになっています。
  0A9F: 32@ = current_thread_pointer
  000A: 32@ += 0x3C
  0085: 14@ = 0@ // (int)
  0012: 14@ *= 4
  005A: 14@ += 32@ // (int)
  0A9F: 13@ = current_thread_pointer
  000A: 13@ += 0x10
  0A8D: 13@ = read_memory 13@ size 4 virtual_protect 0
  000E: 13@ -= @SSCANF_FORMAT
  0A99: chdir 0
  0A9A: 32@ = openfile "cleo\missile.dat" mode 0x6272 // IF and SET
  for 33@ = 0 to 23
  0AA7: call_function 0x536F80 num_params 1 pop 1 32@ 11@
  0A8D: 12@ = read_memory 11@ size 1 virtual_protect 0
  if
  0039: 12@ == 0
  then
  break
  end
  if
  0039: 12@ == 0x3B
  then
  000E: 33@ -= 1
  continue
  end
  0AA5: call 3@(3@,1i) num_params 3 pop 3 11@ 13@ 14@
  000A: 14@ += 0xA0
  end
  0A9B: closefile 32@
  GTA San Andreas\cleo\missile.datを開き、fgets()で1行ずつ読みこみ、
  行頭がNULなら読みこみ中止、行頭がセミコロンならその行を無視します。
  どちらでもない場合は書式にしたがって読み込みます。
  --------------------------------------------------------------------------------
  機械語の埋め込みと実行
  関数ポインタの配列を上のローカル変数の拡張を使用して作成します。
  0A9F: 0@ = current_thread_pointer
  000A: 0@ += 0x10
  0A8D: 0@ = read_memory 0@ size 4 virtual_protect 0
  0085: 0@(3@,1i) = 0@ // (int)
  000E: 0@(3@,1i) -= @FUNC_00
  :FUNC_00には機械語を直接記述します。
  :FUNC_00
  hex
  6A00 // push 0
  6A00 // push 0
  6800007041 // push 15.0
  6A00 // push 0
  68CDCC4C3E // push 0.2
  6A00 // push 0
  6A00 // push 0
  6A00 // push 0
  6A00 // push 0
  6A01 // push 1
  8B4C2430 // mov ecx, [esp+0x30]
  51 // push ecx // Corona Flare
  8B4C2438 // mov ecx, [esp+0x38]
  51 // push ecx // Corona Type
  6800803B45 // push 3000.0
  8B4C2444 // mov ecx, [esp+0x44]
  51 // push ecx // Corona Size
  8D94244C000000 // lea edx, [esp+0x0000004C]
  52 // push edx // Corona Position Pointer
  68FF000000 // push 255 // Corona Alpha
  6880000000 // push 128 // Corona Blue
  68C0000000 // push 192 // Corona Green
  68FF000000 // push 255 // Corona Red
  6A00 // push 0
  8B442454 // mov eax, [esp+0x54]
  03C6 // add eax, esi
  50 // push eax // Corona ID
  B880C56F00 // mov eax, 0x006FC580
  FFD0 // call eax
  83C454 // add esp, 0x54
  C3 // ret
  end
  これはコロナを表示するコードで、色は固定されています。
  表示範囲は3000mまで延長され、IDを指定可能です。
  0AA5: call 0@(3@,1i) num_params 7 pop 7 [Z] [Y] [X] [Size] [Type] [Flare] [ID]
  IDを変更すれば同じ場所から呼び出しても複数表示可能です。
  他にも
  オブジェクトへロケットの音を適用する関数
  爆発を作成する関数
  sscanfを間接的に呼び出す関数
  HitTestを行う関数
  アークタンジェントを求める関数
  座標にオブジェクトの逆マトリクスをかける関数
  があります。
  最後の3つは既存のコード(非公開, #83, #264)と比べるとずっと速くなっています。
  --------------------------------------------------------------------------------
  低級フック
  至極単純。
  フックしたいコードの場所に
  mov eax, [ADDRESS]
  jmp eax
  を埋め込むだけです。
  たとえば携行ロケットの発射をフックしたいなら
  0A9F: 13@ = current_thread_pointer
  000A: 13@ += 0x10
  0A8D: 13@ = read_memory 13@ size 4 virtual_protect 0
  000E: 13@ -= @PROX_RPG
  0A8C: write_memory 0x741A53 size 1 value 0xB8 virtual_protect 1
  0A8C: write_memory 0x741A54 size 4 value 13@ virtual_protect 1
  0A8C: write_memory 0x741A58 size 2 value 0xE0FF virtual_protect 1
  000A: 13@ += 1
  0A9F: 14@ = current_thread_pointer
  0A8C: write_memory 13@ size 4 value 14@ virtual_protect 1
  :PROX_RPG
  hex
  7407 // je +0x07
  B8807C7300 // mov eax, 0x00737C80 // 普通の処理
  FFD0 // call eax
  83C42C // add esp, 0x20 // 処理をスキップ
  B85B1A7400 // mov eax, 0x00741A5B
  FFE0 // jmp eax
  #####################################################################