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

本文转载自小猫的世界MUD,原文链接:https://catworld.muds.me/forum/viewtopic.php?f=23&t=740

一般 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% 的物件數量)

實作範例:

建立共享装备

因為是共享式的物件, 這些裝備並不適合放置於某一隻 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;
}

裝備繼承檔的修改

修改 /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");
    }

// ...略
}

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()); // 武器
        }
    }
}

撰寫 npc 時的改變

原來的寫法

void create() {

// ...略

    carry_object("/obj/area/obj/cloth")->wear();
    carry_object(__DIR__"obj/cane")->wield();
}

共享裝備的寫法


// ...略

    // 調整 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;
    }

// ...略

指令 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;
    }

// ...略

其他注意事項:

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