13号避难所

 找回密码
 立即注册
搜索
查看: 5886|回复: 4
打印 上一主题 下一主题

[辐射2 MOD] 用sfall腳本讓自動槍塔可以被搜刮子彈

[复制链接]
跳转到指定楼层
楼主
发表于 2016-4-10 11:26:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
前言:
自動槍塔本來打壞之後不能搜刮,因為角色檔案內加上了“不能偷竊”的旗標,等於它死後鼠標移到它上頭也不會有“使用/拿取”的圖示。在不用sfall腳本的情況下,需要用16進位編輯器修改自動槍塔的proto檔案(00000480.pro)把“不能偷竊”旗標移除。
但光是這樣還不算完美,因為會變成可以拿到它們本來不該給玩家拿到的武器(裝800發子彈的多管機槍),就算不管沒有正常的武器圖像,光是打壞一個自動槍塔就有多管機槍和一卡車子彈可拿也太不平衡了點,所以還得修改角色對應腳本,在死亡後執行把武器移除與加上適當數量子彈的部份。
這種做法缺點一是得修改個別的proto檔案、二是每種角色有自己的腳本,至少自動槍塔就分成山嶺軍事基地和鑽油平台兩種。同理要是想把哨兵機器人也改成可以搜刮,要動的檔案數量就更多了,還別提可能會和其他mod衝突到,得手動合併修改的部份。
當然這種時候就是需要方便的sfall腳本了,用兩個hook script一個global script就可以把全部細節都顧到,還可以擴充適用對象。

事前準備:

腳本源碼:
global script的部份是修改內存中的proto檔案資料,省去直接修改實際檔案的功夫:
  1. // gl_loot_bots.ssl
  2. procedure start;
  3. #include ".\HEADERS\DEFINE.H"
  4. #include ".\HEADERS\define_extra.h"

  5. procedure start begin
  6.     if(game_loaded) then begin
  7.         set_global_script_repeat(60);
  8.     end else begin
  9.         // Auto-Cannon
  10.         set_proto_data(16777696, PROTO_CR_ACTION_FLAGS, (CFLG_NODROP + CFLG_NOLIMBS + CFLG_NOAGES + CFLG_NOHEAL + CFLG_FLATTN + CFLG_NOKNOCKDOWN));
  11.     end
  12. end
复制代码

define_extra.h要從modders pack裡面取得,set_proto_data後面那堆加起來的玩意兒需要特別解說一下。如果你用16進位編輯器打開自動槍塔的proto檔案(00000480.pro)會看到這樣:


反白的部份就是可對該角色進行動作的旗標,數值是0x00004BE0,而define_extra.h內關於旗標的描述是:
  1. #define CFLG_BARTER             2  //0x00000002 - Barter (can trade with)
  2. #define CFLG_NOSTEAL           32  //0x00000020 - Steal (cannot steal from)
  3. #define CFLG_NODROP            64  //0x00000040 - Drop (doesn't drop items)
  4. #define CFLG_NOLIMBS          128  //0x00000080 - Limbs (cannot lose limbs)
  5. #define CFLG_NOAGES           256  //0x00000100 - Ages (dead body does not disappear)
  6. #define CFLG_NOHEAL           512  //0x00000200 - Heal (damage is not cured with time)
  7. #define CFLG_INVULN          1024  //0x00000400 - Invulnerable (cannot be hurt)
  8. #define CFLG_FLATTN          2048  //0x00000800 - Flatten (leaves no dead body)
  9. #define CFLG_SPECIAL         4096  //0x00001000 - Special (there is a special type of death)
  10. #define CFLG_RANGED          8192  //0x00002000 - Range (melee attack is possible at a distance)
  11. #define CFLG_NOKNOCKDOWN    16384  //0x00004000 - Knock (cannot be knocked down)
复制代码

0x00004BE0可以拆成0x00004000 + 0x00000800 + 0x00000200 + 0x00000100 + 0x00000080 + 0x00000040 + 0x00000020(16進位加法請自行參考相關資料),等於Knock、Flatten、Heal、Ages、Limbs、Drop、Steal七個旗標有被設定起來。
我們想讓自動槍塔可以被執行“使用/拿取”的動作就得把Steal旗標取消,所以新的數值應該要是(0x00004000 + 0x00000800 + 0x00000200 + 0x00000100 + 0x00000080 + 0x00000040) = 0x00004BC0
當然現在用上腳本就不需要自己手動把那些旗標值加總,直接把定義好的旗標變數扔進去用加號兜一起就好。

上面的global script讓自動槍塔可以被偷竊,死後就像一般屍體一樣可以搜刮。不過如果你有辦法摸近山嶺軍事基地槍塔旁邊對它們使用偷竊的話,你會發現可以直接偷到它們的多管機槍,因為它們一開始沒把武器放到手上(原本不可能被偷,自然就隨便些了),鑽油平台上的有特別在角色腳本內寫上地圖一載入就直接裝備武器,所以像你一進大廳才會看到它們執行舉起雙手多管機槍的動作。

當然你可以在山嶺軍事基地槍塔的腳本(WCTURRET.SSL)內也加上同樣自動裝備武器的部份,或是修改地圖檔把它們在背包內的武器放到左手(NPC要使用它們時會切換到右手物品格,你在NPC死前偷不了),不過修改地圖檔要生效得在還沒進入過該地圖才行。
這邊我用第三種方式:限制它們還活著時不能被偷竊。

sfall 3.5版加上了hs_useskill這個hook script,在使用任何技能時都會觸發腳本,所以腳本內容可以簡單這樣寫:
  1. // hs_useskill.ssl
  2. procedure start;
  3. #include ".\HEADERS\DEFINE.H"
  4. #include ".\HEADERS\define_extra.h"

  5. procedure start begin
  6.     variable user, target, skill;
  7.     if not init_hook then begin
  8.         user := get_sfall_arg;
  9.         target := get_sfall_arg;
  10.         skill := get_sfall_arg;
  11.         if ((user == dude_obj) and (skill == SKILL_STEAL)) then begin
  12.             if ((obj_pid(target) == 16777696) and (not (is_critter_dead(target)))) then begin
  13.                 set_sfall_return(0);
  14.             end
  15.         end
  16.     end
  17. end
复制代码

邏輯本身很簡單,如果使用技能者是玩家(dude_obj)而且使用技能是偷竊,就檢查被使用技能的對象,如果對方是自動槍塔(PID為16777696)而且沒有死,腳本就回傳0值。hs_useskill只要回傳數值不是-1,就會擋下角色使用技能後本來該正常執行的其他部份。在遊戲內實際情況是你對它們進行偷竊只會看到自己角色雙手動一動就沒了,不會開啟雙方物品欄。

OK,現在自動槍塔是死後才可以搜刮了,不過這樣你還是會拿到它們的多管機槍,前面已經提過我覺得這樣太不平衡,於是得再動些手腳讓它們死後武器被移除,另外加上一些子彈在它們物品欄內。
舊的正規作法是修改角色各別腳本(WCTURRET.SSL/QCTURRET.SSL)加上destroy_p_proc程序,它們死後會執行destroy_p_proc內的指令。不過可以用一個腳本就能解決的事,何必用上兩個呢?

sfall 1.46版開始就有hs_ondeath這個hook script,在任何角色死亡時都會觸發腳本,不過這腳本就比較複雜了:
  1. // hs_ondeath.ssl
  2. procedure start;
  3. #include ".\HEADERS\DEFINE.H"
  4. #include ".\HEADERS\define_extra.h"

  5. procedure start begin
  6.     variable critter, removed_item, ammo, ammo_count;

  7.     if not init_hook then begin
  8.         critter := get_sfall_arg;
  9.         // Auto-Cannon
  10.         if (obj_pid(critter) == 16777696) then begin
  11.             if (obj_is_carrying_obj_pid(critter, PID_DUAL_MINIGUN)) then begin
  12.                 if (random(0, 1) == 1) then begin
  13.                     ammo := create_object(PID_5MM_AP, 0, 0);
  14.                     ammo_count := random(1, 2);
  15.                     add_mult_objs_to_inven(critter, ammo, ammo_count);
  16.                 end else begin
  17.                     ammo := create_object(PID_5MM_JHP, 0, 0);
  18.                     ammo_count := random(1, 2);
  19.                     add_mult_objs_to_inven(critter, ammo, ammo_count);
  20.                 end
  21.             end

  22.             if ((obj_is_carrying_obj_pid(critter, PID_HEAVY_DUAL_MINIGUN)) and (random(0, 1) == 1)) then begin
  23.                 ammo := create_object(PID_223_FMJ, 0, 0);
  24.                 ammo_count := random(1, 2);
  25.                 add_mult_objs_to_inven(critter, ammo, ammo_count);
  26.             end

  27.             while ((obj_is_carrying_obj_pid(critter, PID_DUAL_MINIGUN)) or (obj_is_carrying_obj_pid(critter, PID_HEAVY_DUAL_MINIGUN))) do begin
  28.                 removed_item := obj_carrying_pid_obj(critter, PID_DUAL_MINIGUN);
  29.                 rm_obj_from_inven(critter, removed_item);
  30.                 destroy_object(removed_item);
  31.                 removed_item := obj_carrying_pid_obj(critter, PID_HEAVY_DUAL_MINIGUN);
  32.                 rm_obj_from_inven(critter, removed_item);
  33.                 destroy_object(removed_item);
  34.             end
  35.         end
  36.     end
  37. end
复制代码

遊戲內自動槍塔拿的武器有兩種,山嶺軍事基地的是拿Dual Minigun,傷害屬性等同復仇者機槍,鑽油平台的是拿傷害更高一級、用.223 FMJ的Heavy Dual Minigun,所以得照不同武器給不同種類彈藥。
我在腳本中寫的方式是拿Dual Minigun的會有50%機率身上放5mm JHP、50%機率是放5mm AP,彈藥數量是隨機1至2份。拿Heavy Dual Minigun的會有50%機率在身上放.223 FMJ,另外50%機率是沒子彈,彈藥數量同樣隨機1至2份。
其實可以不需要用到while ... do迴圈來移除武器,因為它們基本上就只會有一把,那樣只是做得徹底一點保證完全移除。

這三個腳本可以繼續擴充,像是把哨兵機器人也納入,拿多管機槍的死後可以拿到5mm,或是對玩家角色進行修理或科學檢定,加個機率讓你有機會能“拆下”武器(其實是塞一把武器給它們)等等。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
推荐
 楼主| 发表于 2016-4-10 14:30:11 | 只看该作者
如果你是問遊戲內本來的情況,不行。
沙发
发表于 2016-4-10 14:05:53 | 只看该作者
我都忘了,不过炮塔能用修理技能关掉么
地板
 楼主| 发表于 2016-4-10 17:59:44 | 只看该作者
在測試哨兵機器人時注意到件有趣的事,如果它們身上有機器人火箭砲(Robo Rocket Launcher,PID 270)與機器人火箭彈(Robo Rocket Ammo,PID 274),在死的時候就算不用腳本處理,那些物品也會消失掉。
多做了些嘗試,發現應該是遊戲引擎特別針對兩個物品有寫死的處理程序,一些特性如下:
  • 它們物品本身有設定重量(火箭砲重量1、火箭彈6發為一份重量10),但不管是用腳本或是存檔修改器加到自己身上,負重都不會改變,檢視物品時它們本身也沒有顯示重量。
  • 在自己身上時可以看得到物品圖示,一旦放到其他容器或是別人身上,再進入它們物品欄翻一次它們就會從容器中或該NPC身上“消失”。
  • “消失”不是被引擎直接移除,東西應該還是在那邊,比較接近被遊戲遮住的狀態,不過一些特定情況會讓它們再次出現。例如我改了幾把機器人火箭砲和一些機器人火箭彈在自己身上,用偷竊塞一點到路人口袋內,再對他進行一次偷竊就看不到了,然後我拿火箭砲把那路人炸成碎片時,機器人火箭砲與機器人火箭彈就會出現在地上,也可以撿起來。

所以本來打算寫腳本給拿火箭砲的哨兵機器人死後身上加些一般火箭彈的,目前看來完全無法運作,連腳本函式(如obj_is_carrying_obj_pid)都無視那些物品。目前只有一種情況腳本函式可以正常運作,就是死的時候在直接它們身上加一把機器人火箭砲,緊接著的判定就可以找到它,然後給一般的高爆/穿甲火箭彈,但這樣根本是脫褲子放屁,不如直接就給火箭彈算了。類似的情況在其他幾個敵人專用武器上也一樣,例如死爪的爪子、火蜥蜴的噴火、眼球機器人的近戰武器。
5#
发表于 2016-4-15 11:53:18 | 只看该作者
赞,就是说辐射2的运行分成引擎和脚本两部分。感觉挺纠缠的。。。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|Archiver|13号避难所

GMT+8, 2024-4-25 15:06 , Processed in 0.056211 second(s), 15 queries .

快速评论 返回顶部 返回列表