Welcome Guest ( Log In | Register )

欢迎访问本站。游客仅能浏览首页新闻、版块主题、维基条目与资源信息,需登录后方可获得内容发布、话题讨论、维基编辑与资源下载等权限。若无账号请先完成注册流程。
 
Reply to this topicStart new topic
> 用sfall腳本讓自動槍塔可以被搜刮子彈, 目前FO4玩得差不多了....
NovaRain
2016-04-10, 21:09
Post #1


位面旅者
Group Icon
 412
   10

Group: Speaker
Posts: 183
Joined: 2012-02-07
Member No.: 47285


(IMG:http://i85.photobucket.com/albums/k67/NovaRain666/fallout2/turret_f0.gif)
前言:
自動槍塔本來打壞之後不能搜刮,因為角色檔案內加上了“不能偷竊”的旗標,等於它死後鼠標移到它上頭也不會有“使用/拿取”的圖示。在不用sfall腳本的情況下,需要用16進位編輯器修改自動槍塔的proto檔案(00000480.pro)把“不能偷竊”旗標移除。
但光是這樣還不算完美,因為會變成可以拿到它們本來不該給玩家拿到的武器(裝800發子彈的多管機槍),就算不管沒有正常的武器圖像,光是打壞一個自動槍塔就有多管機槍和一卡車子彈可拿也太不平衡了點,所以還得修改角色對應腳本,在死亡後執行把武器移除與加上適當數量子彈的部份。
這種做法缺點一是得修改個別的proto檔案、二是每種角色有自己的腳本,至少自動槍塔就分成山嶺軍事基地和鑽油平台兩種。同理要是想把哨兵機器人也改成可以搜刮,要動的檔案數量就更多了,還別提可能會和其他mod衝突到,得手動合併修改的部份。
當然這種時候就是需要方便的sfall腳本了,用兩個hook script一個global script就可以把全部細節都顧到,還可以擴充適用對象。

事前準備:

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

procedure start begin
    if(game_loaded) then begin
        set_global_script_repeat(60);
    end else begin
        // Auto-Cannon
        set_proto_data(16777696, PROTO_CR_ACTION_FLAGS, (CFLG_NODROP + CFLG_NOLIMBS + CFLG_NOAGES + CFLG_NOHEAL + CFLG_FLATTN + CFLG_NOKNOCKDOWN));
    end
end
define_extra.h要從modders pack裡面取得,set_proto_data後面那堆加起來的玩意兒需要特別解說一下。如果你用16進位編輯器打開自動槍塔的proto檔案(00000480.pro)會看到這樣:
(IMG:http://i85.photobucket.com/albums/k67/NovaRain666/fallout2/proto480.png)

反白的部份就是可對該角色進行動作的旗標,數值是0x00004BE0,而define_extra.h內關於旗標的描述是:
CODE
#define CFLG_BARTER             2  //0x00000002 - Barter (can trade with)
#define CFLG_NOSTEAL           32  //0x00000020 - Steal (cannot steal from)
#define CFLG_NODROP            64  //0x00000040 - Drop (doesn't drop items)
#define CFLG_NOLIMBS          128  //0x00000080 - Limbs (cannot lose limbs)
#define CFLG_NOAGES           256  //0x00000100 - Ages (dead body does not disappear)
#define CFLG_NOHEAL           512  //0x00000200 - Heal (damage is not cured with time)
#define CFLG_INVULN          1024  //0x00000400 - Invulnerable (cannot be hurt)
#define CFLG_FLATTN          2048  //0x00000800 - Flatten (leaves no dead body)
#define CFLG_SPECIAL         4096  //0x00001000 - Special (there is a special type of death)
#define CFLG_RANGED          8192  //0x00002000 - Range (melee attack is possible at a distance)
#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,在使用任何技能時都會觸發腳本,所以腳本內容可以簡單這樣寫:
CODE
// hs_useskill.ssl
procedure start;
#include ".\HEADERS\DEFINE.H"
#include ".\HEADERS\define_extra.h"

procedure start begin
    variable user, target, skill;
    if not init_hook then begin
        user := get_sfall_arg;
        target := get_sfall_arg;
        skill := get_sfall_arg;
        if ((user == dude_obj) and (skill == SKILL_STEAL)) then begin
            if ((obj_pid(target) == 16777696) and (not (is_critter_dead(target)))) then begin
                set_sfall_return(0);
            end
        end
    end
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,在任何角色死亡時都會觸發腳本,不過這腳本就比較複雜了:
CODE
// hs_ondeath.ssl
procedure start;
#include ".\HEADERS\DEFINE.H"
#include ".\HEADERS\define_extra.h"

procedure start begin
    variable critter, removed_item, ammo, ammo_count;

    if not init_hook then begin
        critter := get_sfall_arg;
        // Auto-Cannon
        if (obj_pid(critter) == 16777696) then begin
            if (obj_is_carrying_obj_pid(critter, PID_DUAL_MINIGUN)) then begin
                if (random(0, 1) == 1) then begin
                    ammo := create_object(PID_5MM_AP, 0, 0);
                    ammo_count := random(1, 2);
                    add_mult_objs_to_inven(critter, ammo, ammo_count);
                end else begin
                    ammo := create_object(PID_5MM_JHP, 0, 0);
                    ammo_count := random(1, 2);
                    add_mult_objs_to_inven(critter, ammo, ammo_count);
                end
            end

            if ((obj_is_carrying_obj_pid(critter, PID_HEAVY_DUAL_MINIGUN)) and (random(0, 1) == 1)) then begin
                ammo := create_object(PID_223_FMJ, 0, 0);
                ammo_count := random(1, 2);
                add_mult_objs_to_inven(critter, ammo, ammo_count);
            end

            while ((obj_is_carrying_obj_pid(critter, PID_DUAL_MINIGUN)) or (obj_is_carrying_obj_pid(critter, PID_HEAVY_DUAL_MINIGUN))) do begin
                removed_item := obj_carrying_pid_obj(critter, PID_DUAL_MINIGUN);
                rm_obj_from_inven(critter, removed_item);
                destroy_object(removed_item);
                removed_item := obj_carrying_pid_obj(critter, PID_HEAVY_DUAL_MINIGUN);
                rm_obj_from_inven(critter, removed_item);
                destroy_object(removed_item);
            end
        end
    end
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,或是對玩家角色進行修理/科學檢定,加個機率讓你有機會能“拆下”武器(其實是塞一把武器給它們)等等。

補充事項:
在測試哨兵機器人時注意到件有趣的事,如果它們身上有機器人火箭砲(Robo Rocket Launcher,PID 270)與機器人火箭彈(Robo Rocket Ammo,PID 274),在死的時候就算不用腳本處理,那些物品也會消失掉。
多做了些測試,發現應該是遊戲引擎特別針對那些物品有寫死的處理程序,一些特性如下:
  1. 它們物品本身有設定重量(火箭砲重量1、火箭彈6發為一份重量10),但不管是用腳本或是存檔修改器加到自己身上,負重都不會改變,檢視物品時它們本身也沒有顯示重量。
  2. 在自己身上時可以看得到物品圖示,一旦放到其他容器或是別人身上,再進入它們物品欄翻一次它們就會從容器中或該NPC身上“消失”。
  3. “消失”不是被引擎直接移除,東西應該還是在那邊,比較接近被遊戲遮住的狀態,不過一些特定情況會讓它們再次出現。例如我改了幾把機器人火箭砲和一些機器人火箭彈在自己身上,用偷竊塞一點到路人口袋內,再對他進行一次偷竊就看不到了,然後我拿火箭砲把那路人炸成碎片時,機器人火箭砲與機器人火箭彈就會出現在地上,也可以撿起來。
所以本來打算寫腳本給拿火箭砲的哨兵機器人死後身上加些一般火箭彈的,目前看來完全無法運作,連腳本函式(如obj_is_carrying_obj_pid)都無視那些物品。目前只有一種情況腳本函式可以正常運作,就是死的時候在直接它們身上加一把機器人火箭砲,緊接著的判定就可以找到它,然後給一般的高爆/穿甲火箭彈,但這樣根本是脫褲子放屁,不如直接就給火箭彈算了。類似的情況在其他幾個敵人專用武器上也一樣,例如死爪的爪子、火蜥蜴的噴火、眼球機器人的近戰武器。

This post has been edited by NovaRain: 2016-04-14, 22:50
TOP
wrhunter
2016-04-16, 09:33
Post #2


吹毛求疵的懒汉
Group Icon
 885
   76

Group: Sinker
Posts: 4063
Joined: 2005-07-12
Member No.: 481


记得辐射圣经里提过,在打出超高伤害的情况下,是可能得到原本不会掉落的武器,例如死爪的爪子。
另外就是利用尸体叠加拿大Boss的武器……
TOP
NovaRain
2016-04-16, 11:21
Post #3


位面旅者
Group Icon
 412
   10

Group: Speaker
Posts: 183
Joined: 2012-02-07
Member No.: 47285


QUOTE(wrhunter @ 2016-04-16, 09:33) *

记得辐射圣经里提过,在打出超高伤害的情况下,是可能得到原本不会掉落的武器,例如死爪的爪子。
另外就是利用尸体叠加拿大Boss的武器……
我印象中沒看過因為單純打出超高傷害而拿到不該拿的,比較有可能的是被化成灰炸成肉塊這種裝備會掉落在地上的情況。
TOP
NovaRain
2016-06-11, 11:48
Post #4


位面旅者
Group Icon
 412
   10

Group: Speaker
Posts: 183
Joined: 2012-02-07
Member No.: 47285


QUOTE(NovaRain @ 2016-04-10, 21:09) *
補充事項:
在測試哨兵機器人時注意到件有趣的事,如果它們身上有機器人火箭砲(Robo Rocket Launcher,PID 270)與機器人火箭彈(Robo Rocket Ammo,PID 274),在死的時候就算不用腳本處理,那些物品也會消失掉。
多做了些測試,發現應該是遊戲引擎特別針對那些物品有寫死的處理程序,一些特性如下:
今天才知道上面這些情況的原因:物品proto檔案有個“隱藏物品”(Hidden Item)旗標,設定上了就會有那些特性在。本來NMA有人建議我把自動槍塔的專用武器都加上隱藏物品旗標,這樣就不用在hs_ondeath腳本加上把武器移除的源碼,但隱藏物品不會被腳本函式正確辨認到(還藏得真徹底),反而會讓在死後加上正確彈藥的部份變麻煩。
TOP
Fast ReplyReply to this topicStart new topic
 


Time is now: 2021-02-28, 01:53