[分享] 減少物件數量 裝備篇

回覆文章
jrealm
系統管理員
文章: 1084
註冊時間: 2014-03-31, 23:10

[分享] 減少物件數量 裝備篇

文章 jrealm » 2017-07-03, 11:51

一般 NPC 都會攜帶並使用一把武器與多件防具
這些裝備被運用的方式不外乎是
1. wield/wear/unwield/remove 時變更 NPC 的能力
2. 戰鬥時發生磨損, 間接降低 NPC 的能力
3. 透過 init() 或 heart_beat() 提供其他功能

除非特例, 一般來說 NPC 從生成到死亡只會經歷一場戰鬥,
裝備的磨損量非常之小, 基本上可以忽略 (不要讓 NPC 的裝備發生磨損)

而 wield/wear/unwield/remove 等指令主要透過 set_temp() 將裝備與 NPC 設定一連結
連結建立後, 其實那件裝備就只是躺在 NPC 的 all_inventory() 裡面, 不會有任何功能

結論:
只要能夠無視磨損, 不使用 init() 或 heart_beat() 的裝備
其實只需要一個物件就足夠 (全系統只需 clone 一份, 而且永遠不會呼叫 destruct())
在每個 NPC 都放上一份, 是非常非常浪費系統資源的

(這個機制的效果非常顯著, CW 因此減少了約 15% 的物件數量)

實作範例:

1. 因為是共享式的物件, 這些裝備並不適合放置於某一隻 NPC 身上
所以要先建立一個 "容器" 來放置這些 "共享裝備"
而建立這些物件的時後, 也需要一些額外的特殊手續
綜合上述, room 或 deamon 都可符合要求
在設計上需盡可能的極簡, 有放置物品的容器不可 update/dest, 否則東西就都不見了 XD

建立 /adm/daemons/shared.c

代碼: 選擇全部

// 修改這個檔案一定要 reboot
// 絕對不能使用 update, 否則會導致共享物件全部消失

int query_max_encumbrance() {
    // 最大化容器容量, 如果是 64bit 系統, 這個數字就可以再大些
    return 2147483647;
}

// 建立共享裝備
object load_shared_equip(string file) {
    object source, equip;

    // 載入欲建立共享裝備的正本物件, 就是 clonep() 會回傳 0 的那一種
    source = load_object(file);

    if (source) {
        // 嘗試從正本物件中取出之前建立的副本
        equip = source->query_temp("shared_object");

        if (!equip && inherits(F_EQUIP, source)) {
            equip = new(file);

            // 有數量限制的特殊處理
            if (inherits(THROWING, equip)) {
                equip->set_amount(1000);
            }

            // 標記為共享物件, 呼叫 is_shared() 時會回傳 1
            equip->set_shared();

            // 此 daemon 就是共享裝備的 environment(), 可防止物件被 clean_up() 回收
            equip->move(this_object());

            // 共享裝備只需要一份, 之後再建立的都是直接回傳這一份副本
            source->set_temp("shared_object", equip);
        }
    }

    return equip;
}

2. 裝備繼承檔的修改

修改 /feature/equip.c

代碼: 選擇全部

// 新增成員變數/getter/setter
nosave int shared;

void set_shared() {
    if (previous_object() && file_name(previous_object()) == SHARE_D) {
        shared = 1;

        set("no_drop", 1); // 不能交易
        set("no_get", 1); // 不能拾取
    }
}

int is_shared() {
    return shared;
}

// 增加 function 參數 owner
// 一般裝備是以 environment() 作為 owner, 呼叫時不會傳遞參數
// 共享裝備會傳入 owner, owner 為裝備的使用者
varargs int wear(object owner) {

...略

    if (!shared) {
        owner = environment();
    }

...略

    // 一般裝備才需要檢查是否為使用中
    if (!shared && query("equipped")) return 1;

...略

}

varargs int wield(object owner) {

...略

    if (!shared) {
        owner = environment();
    }

...略

    // 一般裝備才需要檢查是否為使用中
    if (!shared && query("equipped")) return 1;

...略

}

varargs int unequip(object owner) {

...略

    if (!shared) {
        owner = environment();
    }

...略

    // 一般裝備需要移除使用中的標記
    if (!shared) {
        delete("equipped");
    }

...略
}

3. NPC 標準物件的修改

修改 /std/char/npc.c

代碼: 選擇全部

// NPC 設定共享裝備的 function
void apply_shared_equip(string *files) {
    object equip;

    foreach (string file in files) {
        equip = SHARE_D->load_shared_equip(file);

        if (equip->query("armor_prop")) {
            equip->wear(this_object()); // 防具
        } else {
            equip->wield(this_object()); // 武器
        }
    }
}

4. 撰寫 npc 時的改變

原來的寫法

代碼: 選擇全部

void create() {

...略

    carry_object("/obj/area/obj/cloth")->wear();
    carry_object(__DIR__"obj/cane")->wield();
}
共享裝備的寫法

代碼: 選擇全部

void create() {

...略

    // 不使用 carry_object(), 減少物件數量
    apply_shared_equip({
        "/obj/area/obj/cloth",
        __DIR__"obj/cane",
    });
}

5. 指令 look 的修改

代碼: 選擇全部


...略

    // 調整 look npc 時的裝備資料來源
    // 從 all_inventory() 裡找出已裝備的物件
    // 改成
    // 使用 query_temp() 找出已裝備的物件

    mixed equip = obj->query_temp("armor"); // 防具

    inv = mapp(equip) ? values(equip) : ({});

    // 副手武器
    if (equip = obj->query_temp("secondary_weapon")) {
        inv = ({ equip }) + inv;
    }

    // 主手武器
    if (equip = obj->query_temp("weapon")) {
        inv = ({ equip }) + inv;
    }

...略


6. 其他注意事項:
a. 如果要限制武器的數量, 請勿使用此機制
如果要無限量供應武器, 請記得修改 combined 的 set_amount() 控制共享裝備的數量
b. 請於裝備磨損機制中加上檢查 is_shared(), 共享裝備理應不會有任何磨損
c. 如果有卸除/破壞武器的技能, 須針對共享裝備特別處理, 以 unquip() 取代 destruct()
d. 原來的 npc 裝備機制仍然可以正常運行, 不適合共享的裝備, 可繼續使用原來的寫法
e. 如果一件裝備, 只有一隻 NPC 在用, 改用共享裝備仍然是有效益的, 至少可以免去物件 create/destruct 的迴圈

natsu
文章: 3
註冊時間: 2017-06-30, 22:27

Re: [分享] 減少物件數量 裝備篇

文章 natsu » 2017-07-04, 23:04

這種機制裝備就不能讓玩家可以撿對吧?

jrealm
系統管理員
文章: 1084
註冊時間: 2014-03-31, 23:10

Re: [分享] 減少物件數量 裝備篇

文章 jrealm » 2017-07-05, 01:00

natsu 寫:
2017-07-04, 23:04
這種機制裝備就不能讓玩家可以撿對吧?
是的


但凡事都有例外, CW 也是有這樣的需求, 不過數量不多就是了 (CW 是採用讓玩家撿 unknown equip 的方式)
具體就是套用這一篇 減少物件數量 入門篇 的方式
在 die() 裡面呼叫 carry_object()


或是複雜一點的做法
視情況在個別裝備檔設定掉落概率之類的資訊
然後在 CHAR_D 的 make_corpse() 裡面處理
因為我們可以從 query_temp() 得知 NPC 實際的裝備資訊
也就可以視需求 clone 全部或部分的裝備放置於 corpse 供玩家拾取

回覆文章